From 1b1746a4368c960652ca7e4a36aea8a65fa9f319 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 21 Jul 2016 09:15:50 +0200 Subject: [PATCH 01/64] xics_kvm: drop extra checking of kernel_xics_fd We abort a few lines above if kernel_xics_fd == -1. This is only code cleanup. Signed-off-by: Greg Kurz Signed-off-by: David Gibson --- hw/intc/xics_kvm.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index edbd62fd1b..c9caefcf2b 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -329,6 +329,7 @@ static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu) CPUState *cs; ICPState *ss; KVMXICSState *xicskvm = XICS_SPAPR_KVM(xics); + int ret; cs = CPU(cpu); ss = &xics->ss[cs->cpu_index]; @@ -347,19 +348,14 @@ static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu) return; } - if (xicskvm->kernel_xics_fd != -1) { - int ret; - - ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, - xicskvm->kernel_xics_fd, - kvm_arch_vcpu_id(cs)); - if (ret < 0) { - error_report("Unable to connect CPU%ld to kernel XICS: %s", - kvm_arch_vcpu_id(cs), strerror(errno)); - exit(1); - } - ss->cap_irq_xics_enabled = true; + ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, xicskvm->kernel_xics_fd, + kvm_arch_vcpu_id(cs)); + if (ret < 0) { + error_report("Unable to connect CPU%ld to kernel XICS: %s", + kvm_arch_vcpu_id(cs), strerror(errno)); + exit(1); } + ss->cap_irq_xics_enabled = true; } static void xics_kvm_set_nr_irqs(XICSState *xics, uint32_t nr_irqs, From 7804c353a9f93c3eeb3eb744ee4c962fd34bc760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 25 Jul 2016 16:24:41 +0200 Subject: [PATCH 02/64] hw/ppc: include fdt helper routine in a common file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit spapr_pci would also be a good candidate but the macro _FDT is slightly different. It returns and does not exit. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr.c | 11 +---------- hw/ppc/spapr_events.c | 11 +---------- include/hw/ppc/fdt.h | 23 +++++++++++++++++++++++ 3 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 include/hw/ppc/fdt.h diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 30d6800ab3..79d136d194 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -47,6 +47,7 @@ #include "hw/ppc/ppc.h" #include "hw/loader.h" +#include "hw/ppc/fdt.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "hw/pci-host/spapr.h" @@ -299,16 +300,6 @@ static hwaddr spapr_node0_size(void) return machine->ram_size; } -#define _FDT(exp) \ - do { \ - int ret = (exp); \ - if (ret < 0) { \ - fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ - #exp, fdt_strerror(ret)); \ - exit(1); \ - } \ - } while (0) - static void add_str(GString *s, const gchar *s1) { g_string_append_len(s, s1, strlen(s1) + 1); diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index b0668b34a9..4c7b6aeab6 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -32,6 +32,7 @@ #include "hw/qdev.h" #include "sysemu/device_tree.h" +#include "hw/ppc/fdt.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "hw/pci/pci.h" @@ -210,16 +211,6 @@ struct hp_log_full { #define EVENT_MASK_HOTPLUG 0x10000000 #define EVENT_MASK_IO 0x08000000 -#define _FDT(exp) \ - do { \ - int ret = (exp); \ - if (ret < 0) { \ - fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ - #exp, fdt_strerror(ret)); \ - exit(1); \ - } \ - } while (0) - void spapr_events_fdt_skel(void *fdt, uint32_t check_exception_irq) { uint32_t irq_ranges[] = {cpu_to_be32(check_exception_irq), cpu_to_be32(1)}; diff --git a/include/hw/ppc/fdt.h b/include/hw/ppc/fdt.h new file mode 100644 index 0000000000..fff3e1b577 --- /dev/null +++ b/include/hw/ppc/fdt.h @@ -0,0 +1,23 @@ +/* + * QEMU PowerPC helper routines for the device tree. + * + * Copyright (C) 2016 IBM Corp. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef PPC_FDT_H +#define PPC_FDT_H + +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + +#endif /* PPC_FDT_H */ From 706d64675ac2cd72d803cb2f28aa3a332c402ba9 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 26 Jul 2016 17:28:24 +0530 Subject: [PATCH 03/64] target-ppc: Introduce Power9 family The patch adds CPU PVR definition for POWER9 and enables QEMU to launch guests/linux-user in TCG mode. Signed-off-by: Aneesh Kumar K.V [ Added POWER9 alias, POWER9 SPAPR core and dropped MMU defines ] Signed-off-by: Nikunj A Dadhania [dwg: Dropped sPAPR core type again for now] Signed-off-by: David Gibson --- target-ppc/cpu-models.c | 5 +++ target-ppc/cpu-models.h | 1 + target-ppc/cpu-qom.h | 1 + target-ppc/mmu_helper.c | 2 +- target-ppc/translate_init.c | 86 ++++++++++++++++++++++++++++++++++++- 5 files changed, 93 insertions(+), 2 deletions(-) diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c index 5209e63a72..901cf40033 100644 --- a/target-ppc/cpu-models.c +++ b/target-ppc/cpu-models.c @@ -1147,6 +1147,10 @@ "POWER8NVL v1.0") POWERPC_DEF("970_v2.2", CPU_POWERPC_970_v22, 970, "PowerPC 970 v2.2") + + POWERPC_DEF("POWER9_v1.0", CPU_POWERPC_POWER9_BASE, POWER9, + "POWER9 v1.0") + POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970, "PowerPC 970FX v1.0 (G5)") POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970, @@ -1395,6 +1399,7 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { { "POWER8E", "POWER8E_v2.1" }, { "POWER8", "POWER8_v2.0" }, { "POWER8NVL", "POWER8NVL_v1.0" }, + { "POWER9", "POWER9_v1.0" }, { "970", "970_v2.2" }, { "970fx", "970fx_v3.1" }, { "970mp", "970mp_v1.1" }, diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h index f21a44c830..7d9e6a2ca0 100644 --- a/target-ppc/cpu-models.h +++ b/target-ppc/cpu-models.h @@ -562,6 +562,7 @@ enum { CPU_POWERPC_POWER8_v20 = 0x004D0200, CPU_POWERPC_POWER8NVL_BASE = 0x004C0000, CPU_POWERPC_POWER8NVL_v10 = 0x004C0100, + CPU_POWERPC_POWER9_BASE = 0x004E0000, CPU_POWERPC_970_v22 = 0x00390202, CPU_POWERPC_970FX_v10 = 0x00391100, CPU_POWERPC_970FX_v20 = 0x003C0200, diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 286410502f..713deef301 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -86,6 +86,7 @@ enum powerpc_mmu_t { POWERPC_MMU_2_07 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | POWERPC_MMU_64K | POWERPC_MMU_AMR | 0x00000004, + /* FIXME Add POWERPC_MMU_3_OO defines */ /* Architecture 2.07 "degraded" (no 1T segments) */ POWERPC_MMU_2_07a = POWERPC_MMU_64 | POWERPC_MMU_AMR | 0x00000004, diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 3eb3cd78e2..737f338fb9 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -1941,7 +1941,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env) break; default: /* XXX: TODO */ - cpu_abort(CPU(cpu), "Unknown MMU model\n"); + cpu_abort(CPU(cpu), "Unknown MMU model %d\n", env->mmu_model); break; } } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 7a9b15e7e1..2d29ad82cd 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7459,7 +7459,8 @@ enum BOOK3S_CPU_TYPE { BOOK3S_CPU_POWER5PLUS, BOOK3S_CPU_POWER6, BOOK3S_CPU_POWER7, - BOOK3S_CPU_POWER8 + BOOK3S_CPU_POWER8, + BOOK3S_CPU_POWER9 }; static void gen_fscr_facility_check(DisasContext *ctx, int facility_sprn, @@ -8241,6 +8242,7 @@ static void init_proc_book3s_64(CPUPPCState *env, int version) break; case BOOK3S_CPU_POWER7: case BOOK3S_CPU_POWER8: + case BOOK3S_CPU_POWER9: gen_spr_book3s_ids(env); gen_spr_amr(env, version >= BOOK3S_CPU_POWER8); gen_spr_book3s_purr(env); @@ -8293,6 +8295,7 @@ static void init_proc_book3s_64(CPUPPCState *env, int version) break; case BOOK3S_CPU_POWER7: case BOOK3S_CPU_POWER8: + case BOOK3S_CPU_POWER9: default: env->slb_nr = 32; break; @@ -8310,6 +8313,7 @@ static void init_proc_book3s_64(CPUPPCState *env, int version) ppcPOWER7_irq_init(ppc_env_get_cpu(env)); break; case BOOK3S_CPU_POWER8: + case BOOK3S_CPU_POWER9: init_excp_POWER8(env); ppcPOWER7_irq_init(ppc_env_get_cpu(env)); break; @@ -8772,6 +8776,86 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->l1_icache_size = 0x8000; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; } +static void init_proc_POWER9(CPUPPCState *env) +{ + init_proc_book3s_64(env, BOOK3S_CPU_POWER9); +} + +static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr) +{ + if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER9_BASE) { + return true; + } + return false; +} + +POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->fw_name = "PowerPC,POWER9"; + dc->desc = "POWER9"; + dc->props = powerpc_servercpu_properties; + pcc->pvr_match = ppc_pvr_match_power9; + pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07; + pcc->init_proc = init_proc_POWER9; + pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_FRSQRTES | + PPC_FLOAT_STFIWX | + PPC_FLOAT_EXT | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_64B | PPC_64BX | PPC_ALTIVEC | + PPC_SEGMENT_64B | PPC_SLBI | + PPC_POPCNTB | PPC_POPCNTWD | + PPC_CILDST; + pcc->insns_flags2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX | + PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | + PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | + PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | + PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | + PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | + PPC2_TM | PPC2_PM_ISA206; + pcc->msr_mask = (1ull << MSR_SF) | + (1ull << MSR_TM) | + (1ull << MSR_VR) | + (1ull << MSR_VSX) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); + /* Using 2.07 defines until new radix model is added. */ + pcc->mmu_model = POWERPC_MMU_2_07; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; + /* segment page size remain the same */ + pcc->sps = &POWER7_POWER8_sps; +#endif + pcc->excp_model = POWERPC_EXCP_POWER8; + pcc->bus_model = PPC_FLAGS_INPUT_POWER7; + pcc->bfd_mach = bfd_mach_ppc64; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | + POWERPC_FLAG_VSX | POWERPC_FLAG_TM; + pcc->l1_dcache_size = 0x8000; + pcc->l1_icache_size = 0x8000; + pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; +} #if !defined(CONFIG_USER_ONLY) From eb640b13a39b13011273bcaf19e39c81c1d1b03b Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 26 Jul 2016 17:28:25 +0530 Subject: [PATCH 04/64] target-ppc: Introduce POWER ISA 3.0 flag This flag will be used for POWER9 instructions. Signed-off-by: Nikunj A Dadhania Reviewed-by: David Gibson Signed-off-by: David Gibson --- target-ppc/cpu.h | 5 ++++- target-ppc/translate_init.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 786ab5cdfa..d84ea3c1a7 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -2095,6 +2095,8 @@ enum { PPC2_TM = 0x0000000000020000ULL, /* Server PM instructgions (ISA 2.06, Book III) */ PPC2_PM_ISA206 = 0x0000000000040000ULL, + /* POWER ISA 3.0 */ + PPC2_ISA300 = 0x0000000000080000ULL, #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \ @@ -2102,7 +2104,8 @@ enum { PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \ PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \ PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \ - PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206) + PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206 | \ + PPC2_ISA300) }; /*****************************************************************************/ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 2d29ad82cd..6bb4162e6b 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8820,7 +8820,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | - PPC2_TM | PPC2_PM_ISA206; + PPC2_TM | PPC2_PM_ISA206 | PPC2_ISA300; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_TM) | (1ull << MSR_VR) | From c5b2b9ce126a629b45a11353bf315078c21c6904 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 26 Jul 2016 17:28:26 +0530 Subject: [PATCH 05/64] target-ppc: adding addpcis instruction ISA 3.0 instruction for adding immediate value shifted with next instruction address and return the result in the target register. Signed-off-by: Nikunj A Dadhania Reviewed-by: David Gibson Signed-off-by: David Gibson --- target-ppc/translate.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 92030b66a5..ca246ea304 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -432,6 +432,20 @@ static inline uint32_t name(uint32_t opcode) \ return (((opcode >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \ ((opcode >> (shift2)) & ((1 << (nb2)) - 1)); \ } + +#define EXTRACT_HELPER_DXFORM(name, \ + d0_bits, shift_op_d0, shift_d0, \ + d1_bits, shift_op_d1, shift_d1, \ + d2_bits, shift_op_d2, shift_d2) \ +static inline int16_t name(uint32_t opcode) \ +{ \ + return \ + (((opcode >> (shift_op_d0)) & ((1 << (d0_bits)) - 1)) << (shift_d0)) | \ + (((opcode >> (shift_op_d1)) & ((1 << (d1_bits)) - 1)) << (shift_d1)) | \ + (((opcode >> (shift_op_d2)) & ((1 << (d2_bits)) - 1)) << (shift_d2)); \ +} + + /* Opcode part 1 */ EXTRACT_HELPER(opc1, 26, 6); /* Opcode part 2 */ @@ -501,6 +515,9 @@ EXTRACT_HELPER(FPL, 25, 1); EXTRACT_HELPER(FPFLM, 17, 8); EXTRACT_HELPER(FPW, 16, 1); +/* addpcis */ +EXTRACT_HELPER_DXFORM(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0) + /*** Jump target decoding ***/ /* Immediate address */ static inline target_ulong LI(uint32_t opcode) @@ -984,6 +1001,14 @@ static void gen_addis(DisasContext *ctx) } } +/* addpcis */ +static void gen_addpcis(DisasContext *ctx) +{ + target_long d = DX(ctx->opcode); + + tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], ctx->nip + (d << 16)); +} + static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2, int sign, int compute_ov) { @@ -9877,6 +9902,7 @@ GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), +GEN_HANDLER_E(addpcis, 0x13, 0x2, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_HANDLER(mulhw, 0x1F, 0x0B, 0x02, 0x00000400, PPC_INTEGER), GEN_HANDLER(mulhwu, 0x1F, 0x0B, 0x00, 0x00000400, PPC_INTEGER), GEN_HANDLER(mullw, 0x1F, 0x0B, 0x07, 0x00000000, PPC_INTEGER), From f2442ef93c5f032901baceb52811924b71516266 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 26 Jul 2016 17:28:27 +0530 Subject: [PATCH 06/64] target-ppc: add cmprb instruction ISA 3.0 Compare Ranged Byte instruction useful for isupper/islower/isaplha kind of operation. Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index ca246ea304..c64ce79446 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -817,6 +817,44 @@ static void gen_cmpli(DisasContext *ctx) } } +/* cmprb - range comparison: isupper, isaplha, islower*/ +static void gen_cmprb(DisasContext *ctx) +{ + TCGv_i32 src1 = tcg_temp_new_i32(); + TCGv_i32 src2 = tcg_temp_new_i32(); + TCGv_i32 src2lo = tcg_temp_new_i32(); + TCGv_i32 src2hi = tcg_temp_new_i32(); + TCGv_i32 crf = cpu_crf[crfD(ctx->opcode)]; + + tcg_gen_trunc_tl_i32(src1, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_trunc_tl_i32(src2, cpu_gpr[rB(ctx->opcode)]); + + tcg_gen_andi_i32(src1, src1, 0xFF); + tcg_gen_ext8u_i32(src2lo, src2); + tcg_gen_shri_i32(src2, src2, 8); + tcg_gen_ext8u_i32(src2hi, src2); + + tcg_gen_setcond_i32(TCG_COND_LEU, src2lo, src2lo, src1); + tcg_gen_setcond_i32(TCG_COND_LEU, src2hi, src1, src2hi); + tcg_gen_and_i32(crf, src2lo, src2hi); + + if (ctx->opcode & 0x00200000) { + tcg_gen_shri_i32(src2, src2, 8); + tcg_gen_ext8u_i32(src2lo, src2); + tcg_gen_shri_i32(src2, src2, 8); + tcg_gen_ext8u_i32(src2hi, src2); + tcg_gen_setcond_i32(TCG_COND_LEU, src2lo, src2lo, src1); + tcg_gen_setcond_i32(TCG_COND_LEU, src2hi, src1, src2hi); + tcg_gen_and_i32(src2lo, src2lo, src2hi); + tcg_gen_or_i32(crf, crf, src2lo); + } + tcg_gen_shli_i32(crf, crf, CRF_GT); + tcg_temp_free_i32(src1); + tcg_temp_free_i32(src2); + tcg_temp_free_i32(src2lo); + tcg_temp_free_i32(src2hi); +} + /* isel (PowerPC 2.03 specification) */ static void gen_isel(DisasContext *ctx) { @@ -9897,6 +9935,7 @@ GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), GEN_HANDLER_E(cmpb, 0x1F, 0x1C, 0x0F, 0x00000001, PPC_NONE, PPC2_ISA205), +GEN_HANDLER_E(cmprb, 0x1F, 0x00, 0x06, 0x00400001, PPC_NONE, PPC2_ISA300), GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL), GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), From af2c66200ec1458e92a97bbc505244a4817e3f84 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 26 Jul 2016 17:28:28 +0530 Subject: [PATCH 07/64] target-ppc: add modulo word operations Adding following instructions: moduw: Modulo Unsigned Word modsw: Modulo Signed Word Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index c64ce79446..e3d9ac38f3 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1176,6 +1176,52 @@ GEN_DIVE(divde, divde, 0); GEN_DIVE(divdeo, divde, 1); #endif +static inline void gen_op_arith_modw(DisasContext *ctx, TCGv ret, TCGv arg1, + TCGv arg2, int sign) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(t0, arg1); + tcg_gen_trunc_tl_i32(t1, arg2); + if (sign) { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_setcondi_i32(TCG_COND_EQ, t2, t0, INT_MIN); + tcg_gen_setcondi_i32(TCG_COND_EQ, t3, t1, -1); + tcg_gen_and_i32(t2, t2, t3); + tcg_gen_setcondi_i32(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_i32(t2, t2, t3); + tcg_gen_movi_i32(t3, 0); + tcg_gen_movcond_i32(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_rem_i32(t3, t0, t1); + tcg_gen_ext_i32_tl(ret, t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } else { + TCGv_i32 t2 = tcg_const_i32(1); + TCGv_i32 t3 = tcg_const_i32(0); + tcg_gen_movcond_i32(TCG_COND_EQ, t1, t1, t3, t2, t1); + tcg_gen_remu_i32(t3, t0, t1); + tcg_gen_extu_i32_tl(ret, t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +} + +#define GEN_INT_ARITH_MODW(name, opc3, sign) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + gen_op_arith_modw(ctx, cpu_gpr[rD(ctx->opcode)], \ + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ + sign); \ +} + +GEN_INT_ARITH_MODW(moduw, 0x08, 0); +GEN_INT_ARITH_MODW(modsw, 0x18, 1); + /* mulhw mulhw. */ static void gen_mulhw(DisasContext *ctx) { @@ -10242,6 +10288,8 @@ GEN_HANDLER_E(divwe, 0x1F, 0x0B, 0x0D, 0, PPC_NONE, PPC2_DIVE_ISA206), GEN_HANDLER_E(divweo, 0x1F, 0x0B, 0x1D, 0, PPC_NONE, PPC2_DIVE_ISA206), GEN_HANDLER_E(divweu, 0x1F, 0x0B, 0x0C, 0, PPC_NONE, PPC2_DIVE_ISA206), GEN_HANDLER_E(divweuo, 0x1F, 0x0B, 0x1C, 0, PPC_NONE, PPC2_DIVE_ISA206), +GEN_HANDLER_E(modsw, 0x1F, 0x0B, 0x18, 0x00000001, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(moduw, 0x1F, 0x0B, 0x08, 0x00000001, PPC_NONE, PPC2_ISA300), #if defined(TARGET_PPC64) #undef GEN_INT_ARITH_DIVD From 063cf14fe3206ffb37f063245787ccd78f684e2c Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 26 Jul 2016 17:28:29 +0530 Subject: [PATCH 08/64] target-ppc: add modulo dword operations Adding following instructions for ISA3.0 support modud: Modulo Unsigned Dword modsd: Modulo Signed Dword Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson --- target-ppc/translate.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index e3d9ac38f3..90aabb5323 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1222,6 +1222,52 @@ static void glue(gen_, name)(DisasContext *ctx) \ GEN_INT_ARITH_MODW(moduw, 0x08, 0); GEN_INT_ARITH_MODW(modsw, 0x18, 1); +#if defined(TARGET_PPC64) +static inline void gen_op_arith_modd(DisasContext *ctx, TCGv ret, TCGv arg1, + TCGv arg2, int sign) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_mov_i64(t0, arg1); + tcg_gen_mov_i64(t1, arg2); + if (sign) { + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + tcg_gen_setcondi_i64(TCG_COND_EQ, t2, t0, INT64_MIN); + tcg_gen_setcondi_i64(TCG_COND_EQ, t3, t1, -1); + tcg_gen_and_i64(t2, t2, t3); + tcg_gen_setcondi_i64(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_i64(t2, t2, t3); + tcg_gen_movi_i64(t3, 0); + tcg_gen_movcond_i64(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_rem_i64(ret, t0, t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); + } else { + TCGv_i64 t2 = tcg_const_i64(1); + TCGv_i64 t3 = tcg_const_i64(0); + tcg_gen_movcond_i64(TCG_COND_EQ, t1, t1, t3, t2, t1); + tcg_gen_remu_i64(ret, t0, t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); + } + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +} + +#define GEN_INT_ARITH_MODD(name, opc3, sign) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + gen_op_arith_modd(ctx, cpu_gpr[rD(ctx->opcode)], \ + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ + sign); \ +} + +GEN_INT_ARITH_MODD(modud, 0x08, 0); +GEN_INT_ARITH_MODD(modsd, 0x18, 1); +#endif + /* mulhw mulhw. */ static void gen_mulhw(DisasContext *ctx) { @@ -10304,6 +10350,8 @@ GEN_HANDLER_E(divdeu, 0x1F, 0x09, 0x0C, 0, PPC_NONE, PPC2_DIVE_ISA206), GEN_HANDLER_E(divdeuo, 0x1F, 0x09, 0x1C, 0, PPC_NONE, PPC2_DIVE_ISA206), GEN_HANDLER_E(divde, 0x1F, 0x09, 0x0D, 0, PPC_NONE, PPC2_DIVE_ISA206), GEN_HANDLER_E(divdeo, 0x1F, 0x09, 0x1D, 0, PPC_NONE, PPC2_DIVE_ISA206), +GEN_HANDLER_E(modsd, 0x1F, 0x09, 0x18, 0x00000001, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(modud, 0x1F, 0x09, 0x08, 0x00000001, PPC_NONE, PPC2_ISA300), #undef GEN_INT_ARITH_MUL_HELPER #define GEN_INT_ARITH_MUL_HELPER(name, opc3) \ From e91d95b27703c6d67370cb3aa78ed5e4f8b03bbb Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Tue, 26 Jul 2016 17:28:32 +0530 Subject: [PATCH 09/64] target-ppc: add cnttzd[.] instruction Add ISA3.0 Count trailing zeros double word Signed-off-by: Sandipan Das [ added ISA300 flag ] Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 1 + target-ppc/int_helper.c | 5 +++++ target-ppc/translate.c | 10 ++++++++++ 3 files changed, 16 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 1f5cfd0990..0c29c01a0d 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -44,6 +44,7 @@ DEF_HELPER_FLAGS_2(cmpb, TCG_CALL_NO_RWG_SE, tl, tl, tl) DEF_HELPER_3(sraw, tl, env, tl, tl) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(cnttzd, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_2(bpermd, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_3(srad, tl, env, tl, tl) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 74453763d6..93e8dfa1e7 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -150,6 +150,11 @@ target_ulong helper_cntlzd(target_ulong t) { return clz64(t); } + +target_ulong helper_cnttzd(target_ulong t) +{ + return ctz64(t); +} #endif #if defined(TARGET_PPC64) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 90aabb5323..8eea69216e 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1823,6 +1823,15 @@ static void gen_cntlzd(DisasContext *ctx) if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } + +/* cnttzd */ +static void gen_cnttzd(DisasContext *ctx) +{ + gen_helper_cnttzd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } +} #endif /*** Integer rotate ***/ @@ -10060,6 +10069,7 @@ GEN_HANDLER_E(prtyw, 0x1F, 0x1A, 0x04, 0x0000F801, PPC_NONE, PPC2_ISA205), #if defined(TARGET_PPC64) GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD), GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B), +GEN_HANDLER_E(cnttzd, 0x1F, 0x1A, 0x11, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(prtyd, 0x1F, 0x1A, 0x05, 0x0000F801, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(bpermd, 0x1F, 0x1C, 0x07, 0x00000001, PPC_NONE, PPC2_PERM_ISA206), #endif From b35344e4a0968fd1341ec1c1ed2e6b5c0d851542 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 26 Jul 2016 17:28:33 +0530 Subject: [PATCH 10/64] target-ppc: add cnttzw[.] instruction Add ISA3.0: Count trailing zeros word instruction. Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 1 + target-ppc/int_helper.c | 5 +++++ target-ppc/translate.c | 11 +++++++++++ 3 files changed, 17 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 0c29c01a0d..9c79808a64 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -38,6 +38,7 @@ DEF_HELPER_4(divweu, tl, env, tl, tl, i32) DEF_HELPER_4(divwe, tl, env, tl, tl, i32) DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(cnttzw, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_2(cmpb, TCG_CALL_NO_RWG_SE, tl, tl, tl) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 93e8dfa1e7..02b6df3b66 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -145,6 +145,11 @@ target_ulong helper_cntlzw(target_ulong t) return clz32(t); } +target_ulong helper_cnttzw(target_ulong t) +{ + return ctz32(t); +} + #if defined(TARGET_PPC64) target_ulong helper_cntlzd(target_ulong t) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 8eea69216e..b24845344e 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1583,6 +1583,16 @@ static void gen_cntlzw(DisasContext *ctx) if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } + +/* cnttzw */ +static void gen_cnttzw(DisasContext *ctx) +{ + gen_helper_cnttzw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } +} + /* eqv & eqv. */ GEN_LOGICAL2(eqv, tcg_gen_eqv_tl, 0x08, PPC_INTEGER); /* extsb & extsb. */ @@ -10057,6 +10067,7 @@ GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER2(andi_, "andi.", 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER2(andis_, "andis.", 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(cntlzw, 0x1F, 0x1A, 0x00, 0x00000000, PPC_INTEGER), +GEN_HANDLER_E(cnttzw, 0x1F, 0x1A, 0x10, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER), GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER), GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), From 082ce33005d81ff45b929e826ac48a5696059efc Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 26 Jul 2016 17:28:34 +0530 Subject: [PATCH 11/64] target-ppc: add cmpeqb instruction Search a byte in the stream of 8bytes provided in the register Suggested-by: Richard Henderson Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 1 + target-ppc/int_helper.c | 22 ++++++++++++++++++++++ target-ppc/translate.c | 12 ++++++++++++ 3 files changed, 35 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 9c79808a64..9e4bb7b27d 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -44,6 +44,7 @@ DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_2(cmpb, TCG_CALL_NO_RWG_SE, tl, tl, tl) DEF_HELPER_3(sraw, tl, env, tl, tl) #if defined(TARGET_PPC64) +DEF_HELPER_FLAGS_2(cmpeqb, TCG_CALL_NO_RWG_SE, i32, tl, tl) DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(cnttzd, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_NO_RWG_SE, tl, tl) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 02b6df3b66..15947ad925 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -151,6 +151,28 @@ target_ulong helper_cnttzw(target_ulong t) } #if defined(TARGET_PPC64) +/* if x = 0xab, returns 0xababababababababa */ +#define pattern(x) (((x) & 0xff) * (~(target_ulong)0 / 0xff)) + +/* substract 1 from each byte, and with inverse, check if MSB is set at each + * byte. + * i.e. ((0x00 - 0x01) & ~(0x00)) & 0x80 + * (0xFF & 0xFF) & 0x80 = 0x80 (zero found) + */ +#define haszero(v) (((v) - pattern(0x01)) & ~(v) & pattern(0x80)) + +/* When you XOR the pattern and there is a match, that byte will be zero */ +#define hasvalue(x, n) (haszero((x) ^ pattern(n))) + +uint32_t helper_cmpeqb(target_ulong ra, target_ulong rb) +{ + return hasvalue(rb, ra) ? 1 << CRF_GT : 0; +} + +#undef pattern +#undef haszero +#undef hasvalue + target_ulong helper_cntlzd(target_ulong t) { return clz64(t); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index b24845344e..dd2ce587a1 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -855,6 +855,15 @@ static void gen_cmprb(DisasContext *ctx) tcg_temp_free_i32(src2hi); } +#if defined(TARGET_PPC64) +/* cmpeqb */ +static void gen_cmpeqb(DisasContext *ctx) +{ + gen_helper_cmpeqb(cpu_crf[crfD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rB(ctx->opcode)]); +} +#endif + /* isel (PowerPC 2.03 specification) */ static void gen_isel(DisasContext *ctx) { @@ -10045,6 +10054,9 @@ GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), +#if defined(TARGET_PPC64) +GEN_HANDLER_E(cmpeqb, 0x1F, 0x00, 0x07, 0x00600000, PPC_NONE, PPC2_ISA300), +#endif GEN_HANDLER_E(cmpb, 0x1F, 0x1C, 0x0F, 0x00000001, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(cmprb, 0x1F, 0x00, 0x06, 0x00400001, PPC_NONE, PPC2_ISA300), GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL), From dc2ee038daa88222c4e333ffcc81070b8d0656d2 Mon Sep 17 00:00:00 2001 From: Vivek Andrew Sha Date: Tue, 26 Jul 2016 17:28:35 +0530 Subject: [PATCH 12/64] target-ppc: add setb instruction The CR number is provided in the opcode as - BFA (11:13) Returns: -1 if bit 0 of CR field is set 1 if bit 1 of CR field is set 0 otherwise. Signed-off-by: Vivek Andrew Sha [ reworded commit, used 32bit ops as crf is 32bits ] Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index dd2ce587a1..1384fb79b0 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4867,6 +4867,27 @@ static void gen_mtspr(DisasContext *ctx) } } +#if defined(TARGET_PPC64) +/* setb */ +static void gen_setb(DisasContext *ctx) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t8 = tcg_temp_new_i32(); + TCGv_i32 tm1 = tcg_temp_new_i32(); + int crf = crfS(ctx->opcode); + + tcg_gen_setcondi_i32(TCG_COND_GEU, t0, cpu_crf[crf], 4); + tcg_gen_movi_i32(t8, 8); + tcg_gen_movi_i32(tm1, -1); + tcg_gen_movcond_i32(TCG_COND_GEU, t0, cpu_crf[crf], t8, tm1, t0); + tcg_gen_ext_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t8); + tcg_temp_free_i32(tm1); +} +#endif + /*** Cache management ***/ /* dcbf */ @@ -10185,6 +10206,7 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MFTB), GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC), #if defined(TARGET_PPC64) GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B), +GEN_HANDLER_E(setb, 0x1F, 0x00, 0x04, 0x0003F801, PPC_NONE, PPC2_ISA300), #endif GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001EF801, PPC_MISC), GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000000, PPC_MISC), From aeeb044c7bd59ced2b630bf82f644a2137ac9a6f Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 26 Jul 2016 17:28:36 +0530 Subject: [PATCH 13/64] target-ppc: add maddld instruction maddld: Multiply-Add Low Doubleword Multiplies two 64-bit registers (RA * RB), adds third register(RC) to the result(quadword) and returns the lower dword in the target register(RT). Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1384fb79b0..488a105097 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -7740,6 +7740,17 @@ GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20) GEN_VAFORM_PAIRED(vsel, vperm, 21) GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) +#if defined(TARGET_PPC64) +static void gen_maddld(DisasContext *ctx) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_mul_i64(t1, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + tcg_gen_add_i64(cpu_gpr[rD(ctx->opcode)], t1, cpu_gpr[rC(ctx->opcode)]); + tcg_temp_free_i64(t1); +} +#endif /* defined(TARGET_PPC64) */ + GEN_VXFORM_NOA(vclzb, 1, 28) GEN_VXFORM_NOA(vclzh, 1, 29) GEN_VXFORM_NOA(vclzw, 1, 30) @@ -10355,6 +10366,9 @@ GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC), GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC), GEN_HANDLER(mtvscr, 0x04, 0x2, 0x19, 0x03ff0000, PPC_ALTIVEC), GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x00000000, PPC_ALTIVEC), +#if defined(TARGET_PPC64) +GEN_HANDLER_E(maddld, 0x04, 0x19, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300), +#endif GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE), GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE), GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE), From 5f29cc829225f777ca4697cb955572feebaf0748 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 26 Jul 2016 17:28:37 +0530 Subject: [PATCH 14/64] target-ppc: add maddhd and maddhdu instruction maddhd: Multiply-Add High Doubleword maddhdu: Multiply-Add High Doubleword Unsigned Above two instruction are dual form and differ by 1 bit (31st bit) Multiplies two 64-bit registers (RA * RB), adds third register(RC) to the result(quadword) and returns the higher dword in the target register(RT). Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 488a105097..0b21ea28ac 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -7749,6 +7749,29 @@ static void gen_maddld(DisasContext *ctx) tcg_gen_add_i64(cpu_gpr[rD(ctx->opcode)], t1, cpu_gpr[rC(ctx->opcode)]); tcg_temp_free_i64(t1); } + +/* maddhd maddhdu */ +static void gen_maddhd_maddhdu(DisasContext *ctx) +{ + TCGv_i64 lo = tcg_temp_new_i64(); + TCGv_i64 hi = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + if (Rc(ctx->opcode)) { + tcg_gen_mulu2_i64(lo, hi, cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rB(ctx->opcode)]); + tcg_gen_movi_i64(t1, 0); + } else { + tcg_gen_muls2_i64(lo, hi, cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rB(ctx->opcode)]); + tcg_gen_sari_i64(t1, cpu_gpr[rC(ctx->opcode)], 63); + } + tcg_gen_add2_i64(t1, cpu_gpr[rD(ctx->opcode)], lo, hi, + cpu_gpr[rC(ctx->opcode)], t1); + tcg_temp_free_i64(lo); + tcg_temp_free_i64(hi); + tcg_temp_free_i64(t1); +} #endif /* defined(TARGET_PPC64) */ GEN_VXFORM_NOA(vclzb, 1, 28) @@ -10367,6 +10390,8 @@ GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC), GEN_HANDLER(mtvscr, 0x04, 0x2, 0x19, 0x03ff0000, PPC_ALTIVEC), GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x00000000, PPC_ALTIVEC), #if defined(TARGET_PPC64) +GEN_HANDLER_E(maddhd_maddhdu, 0x04, 0x18, 0xFF, 0x00000000, PPC_NONE, + PPC2_ISA300), GEN_HANDLER_E(maddld, 0x04, 0x19, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300), #endif GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE), From 323ad19bcc601d3ec9cb6f0f5b4d67b602fc519e Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 26 Jul 2016 17:28:38 +0530 Subject: [PATCH 15/64] target-ppc: introduce opc4 for Expanded Opcode ISA 3.0 has introduced EO - Expanded Opcode. Introduce third level indirect opcode table and corresponding parsing routines. EO (11:12) Expanded opcode field Formats: XX1 EO (11:15) Expanded opcode field Formats: VX, X, XX2 Signed-off-by: Nikunj A Dadhania [dwg: Trivial checkpatch fixup] Signed-off-by: David Gibson --- target-ppc/translate.c | 82 +++++++++++++++++------ target-ppc/translate_init.c | 127 ++++++++++++++++++++++++++---------- 2 files changed, 155 insertions(+), 54 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 0b21ea28ac..4036bc3442 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -367,12 +367,13 @@ GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, PPC_NONE) #define GEN_HANDLER2_E(name, onam, opc1, opc2, opc3, inval, type, type2) \ GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, type2) +#define GEN_HANDLER_E_2(name, opc1, opc2, opc3, opc4, inval, type, type2) \ +GEN_OPCODE3(name, opc1, opc2, opc3, opc4, inval, type, type2) + typedef struct opcode_t { - unsigned char opc1, opc2, opc3; + unsigned char opc1, opc2, opc3, opc4; #if HOST_LONG_BITS == 64 /* Explicitly align to 64 bits */ - unsigned char pad[5]; -#else - unsigned char pad[1]; + unsigned char pad[4]; #endif opc_handler_t handler; const char *oname; @@ -452,6 +453,8 @@ EXTRACT_HELPER(opc1, 26, 6); EXTRACT_HELPER(opc2, 1, 5); /* Opcode part 3 */ EXTRACT_HELPER(opc3, 6, 5); +/* Opcode part 4 */ +EXTRACT_HELPER(opc4, 16, 5); /* Update Cr0 flags */ EXTRACT_HELPER(Rc, 0, 1); /* Update Cr6 flags (Altivec) */ @@ -589,7 +592,7 @@ EXTRACT_HELPER(SP, 19, 2); .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ - .pad = { 0, }, \ + .opc4 = 0xff, \ .handler = { \ .inval1 = invl, \ .type = _typ, \ @@ -604,7 +607,7 @@ EXTRACT_HELPER(SP, 19, 2); .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ - .pad = { 0, }, \ + .opc4 = 0xff, \ .handler = { \ .inval1 = invl1, \ .inval2 = invl2, \ @@ -620,7 +623,7 @@ EXTRACT_HELPER(SP, 19, 2); .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ - .pad = { 0, }, \ + .opc4 = 0xff, \ .handler = { \ .inval1 = invl, \ .type = _typ, \ @@ -630,13 +633,28 @@ EXTRACT_HELPER(SP, 19, 2); }, \ .oname = onam, \ } +#define GEN_OPCODE3(name, op1, op2, op3, op4, invl, _typ, _typ2) \ +{ \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .opc4 = op4, \ + .handler = { \ + .inval1 = invl, \ + .type = _typ, \ + .type2 = _typ2, \ + .handler = &gen_##name, \ + .oname = stringify(name), \ + }, \ + .oname = stringify(name), \ +} #else #define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2) \ { \ .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ - .pad = { 0, }, \ + .opc4 = 0xff, \ .handler = { \ .inval1 = invl, \ .type = _typ, \ @@ -650,7 +668,7 @@ EXTRACT_HELPER(SP, 19, 2); .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ - .pad = { 0, }, \ + .opc4 = 0xff, \ .handler = { \ .inval1 = invl1, \ .inval2 = invl2, \ @@ -665,7 +683,7 @@ EXTRACT_HELPER(SP, 19, 2); .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ - .pad = { 0, }, \ + .opc4 = 0xff, \ .handler = { \ .inval1 = invl, \ .type = _typ, \ @@ -674,6 +692,20 @@ EXTRACT_HELPER(SP, 19, 2); }, \ .oname = onam, \ } +#define GEN_OPCODE3(name, op1, op2, op3, op4, invl, _typ, _typ2) \ +{ \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .opc4 = op4, \ + .handler = { \ + .inval1 = invl, \ + .type = _typ, \ + .type2 = _typ2, \ + .handler = &gen_##name, \ + }, \ + .oname = stringify(name), \ +} #endif /* SPR load/store helpers */ @@ -11905,9 +11937,10 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) } else { ctx.opcode = cpu_ldl_code(env, ctx.nip); } - LOG_DISAS("translate opcode %08x (%02x %02x %02x) (%s)\n", - ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.le_mode ? "little" : "big"); + LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n", + ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), + opc3(ctx.opcode), opc4(ctx.opcode), + ctx.le_mode ? "little" : "big"); ctx.nip += 4; table = env->opcodes; handler = table[opc1(ctx.opcode)]; @@ -11917,14 +11950,20 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) if (is_indirect_opcode(handler)) { table = ind_table(handler); handler = table[opc3(ctx.opcode)]; + if (is_indirect_opcode(handler)) { + table = ind_table(handler); + handler = table[opc4(ctx.opcode)]; + } } } /* Is opcode *REALLY* valid ? */ if (unlikely(handler->handler == &gen_invalid)) { qemu_log_mask(LOG_GUEST_ERROR, "invalid/unsupported opcode: " - "%02x - %02x - %02x (%08x) " TARGET_FMT_lx " %d\n", + "%02x - %02x - %02x - %02x (%08x) " + TARGET_FMT_lx " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); + opc3(ctx.opcode), opc4(ctx.opcode), + ctx.opcode, ctx.nip - 4, (int)msr_ir); } else { uint32_t inval; @@ -11936,9 +11975,10 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) if (unlikely((ctx.opcode & inval) != 0)) { qemu_log_mask(LOG_GUEST_ERROR, "invalid bits: %08x for opcode: " - "%02x - %02x - %02x (%08x) " TARGET_FMT_lx "\n", - ctx.opcode & inval, opc1(ctx.opcode), - opc2(ctx.opcode), opc3(ctx.opcode), + "%02x - %02x - %02x - %02x (%08x) " + TARGET_FMT_lx "\n", ctx.opcode & inval, + opc1(ctx.opcode), opc2(ctx.opcode), + opc3(ctx.opcode), opc4(ctx.opcode), ctx.opcode, ctx.nip - 4); gen_inval_exception(ctxp, POWERPC_EXCP_INVAL_INVAL); break; @@ -11965,9 +12005,9 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) break; } if (tcg_check_temp_count()) { - fprintf(stderr, "Opcode %02x %02x %02x (%08x) leaked temporaries\n", - opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), - ctx.opcode); + fprintf(stderr, "Opcode %02x %02x %02x %02x (%08x) leaked " + "temporaries\n", opc1(ctx.opcode), opc2(ctx.opcode), + opc3(ctx.opcode), opc4(ctx.opcode), ctx.opcode); exit(1); } } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 6bb4162e6b..293cc3d3d8 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9253,13 +9253,47 @@ static int register_dblind_insn (opc_handler_t **ppc_opcodes, return 0; } +static int register_trplind_insn(opc_handler_t **ppc_opcodes, + unsigned char idx1, unsigned char idx2, + unsigned char idx3, unsigned char idx4, + opc_handler_t *handler) +{ + opc_handler_t **table; + + if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { + printf("*** ERROR: unable to join indirect table idx " + "[%02x-%02x]\n", idx1, idx2); + return -1; + } + table = ind_table(ppc_opcodes[idx1]); + if (register_ind_in_table(table, idx2, idx3, NULL) < 0) { + printf("*** ERROR: unable to join 2nd-level indirect table idx " + "[%02x-%02x-%02x]\n", idx1, idx2, idx3); + return -1; + } + table = ind_table(table[idx2]); + if (register_ind_in_table(table, idx3, idx4, handler) < 0) { + printf("*** ERROR: unable to insert opcode " + "[%02x-%02x-%02x-%02x]\n", idx1, idx2, idx3, idx4); + return -1; + } + return 0; +} static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn) { if (insn->opc2 != 0xFF) { if (insn->opc3 != 0xFF) { - if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2, - insn->opc3, &insn->handler) < 0) - return -1; + if (insn->opc4 != 0xFF) { + if (register_trplind_insn(ppc_opcodes, insn->opc1, insn->opc2, + insn->opc3, insn->opc4, + &insn->handler) < 0) { + return -1; + } + } else { + if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2, + insn->opc3, &insn->handler) < 0) + return -1; + } } else { if (register_ind_insn(ppc_opcodes, insn->opc1, insn->opc2, &insn->handler) < 0) @@ -9335,7 +9369,7 @@ static void dump_ppc_insns (CPUPPCState *env) { opc_handler_t **table, *handler; const char *p, *q; - uint8_t opc1, opc2, opc3; + uint8_t opc1, opc2, opc3, opc4; printf("Instructions set:\n"); /* opc1 is 6 bits long */ @@ -9355,34 +9389,51 @@ static void dump_ppc_insns (CPUPPCState *env) for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN; opc3++) { handler = table[opc3]; - if (handler->handler != &gen_invalid) { - /* Special hack to properly dump SPE insns */ - p = strchr(handler->oname, '_'); - if (p == NULL) { - printf("INSN: %02x %02x %02x (%02d %04d) : " - "%s\n", - opc1, opc2, opc3, opc1, - (opc3 << 5) | opc2, - handler->oname); - } else { - q = "speundef"; - if ((p - handler->oname) != strlen(q) || - memcmp(handler->oname, q, strlen(q)) != 0) { - /* First instruction */ - printf("INSN: %02x %02x %02x (%02d %04d) : " - "%.*s\n", - opc1, opc2 << 1, opc3, opc1, - (opc3 << 6) | (opc2 << 1), - (int)(p - handler->oname), + if (is_indirect_opcode(handler)) { + table = ind_table(handler); + /* opc4 is 5 bits long */ + for (opc4 = 0; opc4 < PPC_CPU_INDIRECT_OPCODES_LEN; + opc4++) { + handler = table[opc4]; + if (handler->handler != &gen_invalid) { + printf("INSN: %02x %02x %02x %02x -- " + "(%02d %04d %02d) : %s\n", + opc1, opc2, opc3, opc4, + opc1, (opc3 << 5) | opc2, opc4, handler->oname); } - if (strcmp(p + 1, q) != 0) { - /* Second instruction */ + } + } else { + if (handler->handler != &gen_invalid) { + /* Special hack to properly dump SPE insns */ + p = strchr(handler->oname, '_'); + if (p == NULL) { printf("INSN: %02x %02x %02x (%02d %04d) : " "%s\n", - opc1, (opc2 << 1) | 1, opc3, opc1, - (opc3 << 6) | (opc2 << 1) | 1, - p + 1); + opc1, opc2, opc3, opc1, + (opc3 << 5) | opc2, + handler->oname); + } else { + q = "speundef"; + if ((p - handler->oname) != strlen(q) + || (memcmp(handler->oname, q, strlen(q)) + != 0)) { + /* First instruction */ + printf("INSN: %02x %02x %02x" + "(%02d %04d) : %.*s\n", + opc1, opc2 << 1, opc3, opc1, + (opc3 << 6) | (opc2 << 1), + (int)(p - handler->oname), + handler->oname); + } + if (strcmp(p + 1, q) != 0) { + /* Second instruction */ + printf("INSN: %02x %02x %02x " + "(%02d %04d) : %s\n", opc1, + (opc2 << 1) | 1, opc3, opc1, + (opc3 << 6) | (opc2 << 1) | 1, + p + 1); + } } } } @@ -9858,8 +9909,8 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp) { PowerPCCPU *cpu = POWERPC_CPU(dev); CPUPPCState *env = &cpu->env; - opc_handler_t **table; - int i, j; + opc_handler_t **table, **table_2; + int i, j, k; cpu_exec_exit(CPU(dev)); @@ -9870,10 +9921,20 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp) if (is_indirect_opcode(env->opcodes[i])) { table = ind_table(env->opcodes[i]); for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) { - if (table[j] != &invalid_handler && - is_indirect_opcode(table[j])) { + if (table[j] == &invalid_handler) { + continue; + } + if (is_indirect_opcode(table[j])) { + table_2 = ind_table(table[j]); + for (k = 0; k < PPC_CPU_INDIRECT_OPCODES_LEN; k++) { + if (table_2[k] != &invalid_handler && + is_indirect_opcode(table_2[k])) { + g_free((opc_handler_t *)((uintptr_t)table_2[k] & + ~PPC_INDIRECT)); + } + } g_free((opc_handler_t *)((uintptr_t)table[j] & - ~PPC_INDIRECT)); + ~PPC_INDIRECT)); } } g_free((opc_handler_t *)((uintptr_t)env->opcodes[i] & From db789c6cd3383e472c2de0115c3d3fa4b2e5c825 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:19 +1000 Subject: [PATCH 16/64] ppc: Provide basic raise_exception_* functions Instead of using the same helpers called from translate.c, let's have a bunch of functions that take the various argument combinations, especially the retaddr which will be needed in subsequent patches, and leave the helpers to be just that, helpers for translate.c We don't yet convert all users, we'll go through them in subsequent patches. Signed-off-by: Benjamin Herrenschmidt -- v2. Fix raise_exception_ra() to properly pass raddr Signed-off-by: David Gibson --- target-ppc/cpu.h | 8 +++++++ target-ppc/excp_helper.c | 51 ++++++++++++++++++++++++++-------------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index d84ea3c1a7..a872efb887 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -2299,6 +2299,14 @@ static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, *flags = env->hflags; } +void QEMU_NORETURN raise_exception(CPUPPCState *env, uint32_t exception); +void QEMU_NORETURN raise_exception_ra(CPUPPCState *env, uint32_t exception, + uintptr_t raddr); +void QEMU_NORETURN raise_exception_err(CPUPPCState *env, uint32_t exception, + uint32_t error_code); +void QEMU_NORETURN raise_exception_err_ra(CPUPPCState *env, uint32_t exception, + uint32_t error_code, uintptr_t raddr); + #if !defined(CONFIG_USER_ONLY) static inline int booke206_tlbm_id(CPUPPCState *env, ppcmas_tlb_t *tlbm) { diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index d6e1678a63..96c6fd9eb0 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -898,34 +898,53 @@ static void cpu_dump_rfi(target_ulong RA, target_ulong msr) /*****************************************************************************/ /* Exceptions processing helpers */ -void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, - uint32_t error_code) +void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, + uint32_t error_code, uintptr_t raddr) { CPUState *cs = CPU(ppc_env_get_cpu(env)); -#if 0 - printf("Raise exception %3x code : %d\n", exception, error_code); -#endif cs->exception_index = exception; env->error_code = error_code; - cpu_loop_exit(cs); + cpu_loop_exit_restore(cs, raddr); +} + +void raise_exception_err(CPUPPCState *env, uint32_t exception, + uint32_t error_code) +{ + raise_exception_err_ra(env, exception, error_code, 0); +} + +void raise_exception(CPUPPCState *env, uint32_t exception) +{ + raise_exception_err_ra(env, exception, 0, 0); +} + +void raise_exception_ra(CPUPPCState *env, uint32_t exception, + uintptr_t raddr) +{ + raise_exception_err_ra(env, exception, 0, raddr); +} + +void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, + uint32_t error_code) +{ + raise_exception_err_ra(env, exception, error_code, 0); } void helper_raise_exception(CPUPPCState *env, uint32_t exception) { - helper_raise_exception_err(env, exception, 0); + raise_exception_err_ra(env, exception, 0, 0); } #if !defined(CONFIG_USER_ONLY) void helper_store_msr(CPUPPCState *env, target_ulong val) { - CPUState *cs; + uint32_t excp = hreg_store_msr(env, val, 0); - val = hreg_store_msr(env, val, 0); - if (val != 0) { - cs = CPU(ppc_env_get_cpu(env)); + if (excp != 0) { + CPUState *cs = CPU(ppc_env_get_cpu(env)); cs->interrupt_request |= CPU_INTERRUPT_EXITTB; - helper_raise_exception(env, val); + raise_exception(env, excp); } } @@ -951,7 +970,7 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) * but this doesn't seem to be a problem. */ env->msr |= (1ull << MSR_EE); - helper_raise_exception(env, EXCP_HLT); + raise_exception(env, EXCP_HLT); } #endif /* defined(TARGET_PPC64) */ @@ -1041,8 +1060,7 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_TRAP); + raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); } } @@ -1055,8 +1073,7 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_TRAP); + raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); } } #endif From f96511215da118ffc635c2c3698c60bf519372ce Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:20 +1000 Subject: [PATCH 17/64] ppc: Move classic fp ops out of translate.c Makes things a bit more manageable Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate.c | 1205 +------------------------------- target-ppc/translate/fp-impl.c | 1098 +++++++++++++++++++++++++++++ target-ppc/translate/fp-ops.c | 111 +++ 3 files changed, 1213 insertions(+), 1201 deletions(-) create mode 100644 target-ppc/translate/fp-impl.c create mode 100644 target-ppc/translate/fp-ops.c diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 4036bc3442..98de1856be 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -250,17 +250,6 @@ struct opc_handler_t { #endif }; -static inline void gen_reset_fpstatus(void) -{ - gen_helper_reset_fpstatus(cpu_env); -} - -static inline void gen_compute_fprf(TCGv_i64 arg) -{ - gen_helper_compute_fprf(cpu_env, arg); - gen_helper_float_check_status(cpu_env); -} - static inline void gen_set_access_type(DisasContext *ctx, int access_type) { if (ctx->access_type != access_type) { @@ -2341,602 +2330,6 @@ static void gen_srd(DisasContext *ctx) } #endif -#if defined(TARGET_PPC64) -static void gen_set_cr1_from_fpscr(DisasContext *ctx) -{ - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_trunc_tl_i32(tmp, cpu_fpscr); - tcg_gen_shri_i32(cpu_crf[1], tmp, 28); - tcg_temp_free_i32(tmp); -} -#else -static void gen_set_cr1_from_fpscr(DisasContext *ctx) -{ - tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28); -} -#endif - -/*** Floating-Point arithmetic ***/ -#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \ -static void gen_f##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ - gen_reset_fpstatus(); \ - gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rA(ctx->opcode)], \ - cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \ - if (isfloat) { \ - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rD(ctx->opcode)]); \ - } \ - if (set_fprf) { \ - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ - } \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ -} - -#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \ -_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type); \ -_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type); - -#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type) \ -static void gen_f##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ - gen_reset_fpstatus(); \ - gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rA(ctx->opcode)], \ - cpu_fpr[rB(ctx->opcode)]); \ - if (isfloat) { \ - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rD(ctx->opcode)]); \ - } \ - if (set_fprf) { \ - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ - } \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ -} -#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \ -_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ -_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type); - -#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type) \ -static void gen_f##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ - gen_reset_fpstatus(); \ - gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rA(ctx->opcode)], \ - cpu_fpr[rC(ctx->opcode)]); \ - if (isfloat) { \ - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rD(ctx->opcode)]); \ - } \ - if (set_fprf) { \ - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ - } \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ -} -#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \ -_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ -_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type); - -#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ -static void gen_f##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ - gen_reset_fpstatus(); \ - gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rB(ctx->opcode)]); \ - if (set_fprf) { \ - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ - } \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ -} - -#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \ -static void gen_f##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ - gen_reset_fpstatus(); \ - gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rB(ctx->opcode)]); \ - if (set_fprf) { \ - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ - } \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ -} - -/* fadd - fadds */ -GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT); -/* fdiv - fdivs */ -GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT); -/* fmul - fmuls */ -GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT); - -/* fre */ -GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT); - -/* fres */ -GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES); - -/* frsqrte */ -GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE); - -/* frsqrtes */ -static void gen_frsqrtes(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); - gen_reset_fpstatus(); - gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env, - cpu_fpr[rB(ctx->opcode)]); - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, - cpu_fpr[rD(ctx->opcode)]); - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode) != 0)) { - gen_set_cr1_from_fpscr(ctx); - } -} - -/* fsel */ -_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL); -/* fsub - fsubs */ -GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT); -/* Optional: */ - -/* fsqrt */ -static void gen_fsqrt(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); - gen_reset_fpstatus(); - gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env, - cpu_fpr[rB(ctx->opcode)]); - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode) != 0)) { - gen_set_cr1_from_fpscr(ctx); - } -} - -static void gen_fsqrts(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); - gen_reset_fpstatus(); - gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env, - cpu_fpr[rB(ctx->opcode)]); - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, - cpu_fpr[rD(ctx->opcode)]); - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode) != 0)) { - gen_set_cr1_from_fpscr(ctx); - } -} - -/*** Floating-Point multiply-and-add ***/ -/* fmadd - fmadds */ -GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT); -/* fmsub - fmsubs */ -GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT); -/* fnmadd - fnmadds */ -GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT); -/* fnmsub - fnmsubs */ -GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT); - -/*** Floating-Point round & convert ***/ -/* fctiw */ -GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT); -/* fctiwu */ -GEN_FLOAT_B(ctiwu, 0x0E, 0x04, 0, PPC2_FP_CVT_ISA206); -/* fctiwz */ -GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT); -/* fctiwuz */ -GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206); -/* frsp */ -GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT); -/* fcfid */ -GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64); -/* fcfids */ -GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206); -/* fcfidu */ -GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); -/* fcfidus */ -GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); -/* fctid */ -GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64); -/* fctidu */ -GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206); -/* fctidz */ -GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64); -/* fctidu */ -GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206); - -/* frin */ -GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT); -/* friz */ -GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT); -/* frip */ -GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT); -/* frim */ -GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT); - -static void gen_ftdiv(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], - cpu_fpr[rB(ctx->opcode)]); -} - -static void gen_ftsqrt(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); -} - - - -/*** Floating-Point compare ***/ - -/* fcmpo */ -static void gen_fcmpo(DisasContext *ctx) -{ - TCGv_i32 crf; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); - gen_reset_fpstatus(); - crf = tcg_const_i32(crfD(ctx->opcode)); - gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)], - cpu_fpr[rB(ctx->opcode)], crf); - tcg_temp_free_i32(crf); - gen_helper_float_check_status(cpu_env); -} - -/* fcmpu */ -static void gen_fcmpu(DisasContext *ctx) -{ - TCGv_i32 crf; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); - gen_reset_fpstatus(); - crf = tcg_const_i32(crfD(ctx->opcode)); - gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)], - cpu_fpr[rB(ctx->opcode)], crf); - tcg_temp_free_i32(crf); - gen_helper_float_check_status(cpu_env); -} - -/*** Floating-point move ***/ -/* fabs */ -/* XXX: beware that fabs never checks for NaNs nor update FPSCR */ -static void gen_fabs(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - tcg_gen_andi_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], - ~(1ULL << 63)); - if (unlikely(Rc(ctx->opcode))) { - gen_set_cr1_from_fpscr(ctx); - } -} - -/* fmr - fmr. */ -/* XXX: beware that fmr never checks for NaNs nor update FPSCR */ -static void gen_fmr(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode))) { - gen_set_cr1_from_fpscr(ctx); - } -} - -/* fnabs */ -/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */ -static void gen_fnabs(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - tcg_gen_ori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], - 1ULL << 63); - if (unlikely(Rc(ctx->opcode))) { - gen_set_cr1_from_fpscr(ctx); - } -} - -/* fneg */ -/* XXX: beware that fneg never checks for NaNs nor update FPSCR */ -static void gen_fneg(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - tcg_gen_xori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], - 1ULL << 63); - if (unlikely(Rc(ctx->opcode))) { - gen_set_cr1_from_fpscr(ctx); - } -} - -/* fcpsgn: PowerPC 2.05 specification */ -/* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */ -static void gen_fcpsgn(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], - cpu_fpr[rB(ctx->opcode)], 0, 63); - if (unlikely(Rc(ctx->opcode))) { - gen_set_cr1_from_fpscr(ctx); - } -} - -static void gen_fmrgew(DisasContext *ctx) -{ - TCGv_i64 b0; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - b0 = tcg_temp_new_i64(); - tcg_gen_shri_i64(b0, cpu_fpr[rB(ctx->opcode)], 32); - tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], - b0, 0, 32); - tcg_temp_free_i64(b0); -} - -static void gen_fmrgow(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], - cpu_fpr[rB(ctx->opcode)], - cpu_fpr[rA(ctx->opcode)], - 32, 32); -} - -/*** Floating-Point status & ctrl register ***/ - -/* mcrfs */ -static void gen_mcrfs(DisasContext *ctx) -{ - TCGv tmp = tcg_temp_new(); - TCGv_i32 tmask; - TCGv_i64 tnew_fpscr = tcg_temp_new_i64(); - int bfa; - int nibble; - int shift; - - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - bfa = crfS(ctx->opcode); - nibble = 7 - bfa; - shift = 4 * nibble; - tcg_gen_shri_tl(tmp, cpu_fpscr, shift); - tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], tmp); - tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], 0xf); - tcg_temp_free(tmp); - tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr); - /* Only the exception bits (including FX) should be cleared if read */ - tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr, ~((0xF << shift) & FP_EX_CLEAR_BITS)); - /* FEX and VX need to be updated, so don't set fpscr directly */ - tmask = tcg_const_i32(1 << nibble); - gen_helper_store_fpscr(cpu_env, tnew_fpscr, tmask); - tcg_temp_free_i32(tmask); - tcg_temp_free_i64(tnew_fpscr); -} - -/* mffs */ -static void gen_mffs(DisasContext *ctx) -{ - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - gen_reset_fpstatus(); - tcg_gen_extu_tl_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr); - if (unlikely(Rc(ctx->opcode))) { - gen_set_cr1_from_fpscr(ctx); - } -} - -/* mtfsb0 */ -static void gen_mtfsb0(DisasContext *ctx) -{ - uint8_t crb; - - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - crb = 31 - crbD(ctx->opcode); - gen_reset_fpstatus(); - if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) { - TCGv_i32 t0; - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); - t0 = tcg_const_i32(crb); - gen_helper_fpscr_clrbit(cpu_env, t0); - tcg_temp_free_i32(t0); - } - if (unlikely(Rc(ctx->opcode) != 0)) { - tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); - tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); - } -} - -/* mtfsb1 */ -static void gen_mtfsb1(DisasContext *ctx) -{ - uint8_t crb; - - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - crb = 31 - crbD(ctx->opcode); - gen_reset_fpstatus(); - /* XXX: we pretend we can only do IEEE floating-point computations */ - if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) { - TCGv_i32 t0; - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); - t0 = tcg_const_i32(crb); - gen_helper_fpscr_setbit(cpu_env, t0); - tcg_temp_free_i32(t0); - } - if (unlikely(Rc(ctx->opcode) != 0)) { - tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); - tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); - } - /* We can raise a differed exception */ - gen_helper_float_check_status(cpu_env); -} - -/* mtfsf */ -static void gen_mtfsf(DisasContext *ctx) -{ - TCGv_i32 t0; - int flm, l, w; - - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - flm = FPFLM(ctx->opcode); - l = FPL(ctx->opcode); - w = FPW(ctx->opcode); - if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) { - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); - return; - } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); - gen_reset_fpstatus(); - if (l) { - t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff); - } else { - t0 = tcg_const_i32(flm << (w * 8)); - } - gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0); - tcg_temp_free_i32(t0); - if (unlikely(Rc(ctx->opcode) != 0)) { - tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); - tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); - } - /* We can raise a differed exception */ - gen_helper_float_check_status(cpu_env); -} - -/* mtfsfi */ -static void gen_mtfsfi(DisasContext *ctx) -{ - int bf, sh, w; - TCGv_i64 t0; - TCGv_i32 t1; - - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - w = FPW(ctx->opcode); - bf = FPBF(ctx->opcode); - if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) { - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); - return; - } - sh = (8 * w) + 7 - bf; - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); - gen_reset_fpstatus(); - t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh)); - t1 = tcg_const_i32(1 << sh); - gen_helper_store_fpscr(cpu_env, t0, t1); - tcg_temp_free_i64(t0); - tcg_temp_free_i32(t1); - if (unlikely(Rc(ctx->opcode) != 0)) { - tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); - tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); - } - /* We can raise a differed exception */ - gen_helper_float_check_status(cpu_env); -} - /*** Addressing modes ***/ /* Register indirect with immediate index : EA = (rA|0) + SIMM */ static inline void gen_addr_imm_index(DisasContext *ctx, TCGv EA, @@ -3881,336 +3274,6 @@ static void gen_rvwinkle(DisasContext *ctx) } #endif /* #if defined(TARGET_PPC64) */ -/*** Floating-point load ***/ -#define GEN_LDF(name, ldop, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_LDUF(name, ldop, opc, type) \ -static void glue(gen_, name##u)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - if (unlikely(rA(ctx->opcode) == 0)) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_LDUXF(name, ldop, opc, type) \ -static void glue(gen_, name##ux)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - if (unlikely(rA(ctx->opcode) == 0)) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_LDXF(name, ldop, opc2, opc3, type) \ -static void glue(gen_, name##x)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_LDFS(name, ldop, op, type) \ -GEN_LDF(name, ldop, op | 0x20, type); \ -GEN_LDUF(name, ldop, op | 0x21, type); \ -GEN_LDUXF(name, ldop, op | 0x01, type); \ -GEN_LDXF(name, ldop, 0x17, op | 0x00, type) - -static inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) -{ - TCGv t0 = tcg_temp_new(); - TCGv_i32 t1 = tcg_temp_new_i32(); - gen_qemu_ld32u(ctx, t0, arg2); - tcg_gen_trunc_tl_i32(t1, t0); - tcg_temp_free(t0); - gen_helper_float32_to_float64(arg1, cpu_env, t1); - tcg_temp_free_i32(t1); -} - - /* lfd lfdu lfdux lfdx */ -GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT); - /* lfs lfsu lfsux lfsx */ -GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT); - -/* lfdp */ -static void gen_lfdp(DisasContext *ctx) -{ - TCGv EA; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - gen_set_access_type(ctx, ACCESS_FLOAT); - EA = tcg_temp_new(); - gen_addr_imm_index(ctx, EA, 0); - /* We only need to swap high and low halves. gen_qemu_ld64 does necessary - 64-bit byteswap already. */ - if (unlikely(ctx->le_mode)) { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); - tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); - } else { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); - tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); - } - tcg_temp_free(EA); -} - -/* lfdpx */ -static void gen_lfdpx(DisasContext *ctx) -{ - TCGv EA; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - gen_set_access_type(ctx, ACCESS_FLOAT); - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - /* We only need to swap high and low halves. gen_qemu_ld64 does necessary - 64-bit byteswap already. */ - if (unlikely(ctx->le_mode)) { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); - tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); - } else { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); - tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); - } - tcg_temp_free(EA); -} - -/* lfiwax */ -static void gen_lfiwax(DisasContext *ctx) -{ - TCGv EA; - TCGv t0; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - gen_set_access_type(ctx, ACCESS_FLOAT); - EA = tcg_temp_new(); - t0 = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - gen_qemu_ld32s(ctx, t0, EA); - tcg_gen_ext_tl_i64(cpu_fpr[rD(ctx->opcode)], t0); - tcg_temp_free(EA); - tcg_temp_free(t0); -} - -/* lfiwzx */ -static void gen_lfiwzx(DisasContext *ctx) -{ - TCGv EA; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - gen_set_access_type(ctx, ACCESS_FLOAT); - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - gen_qemu_ld32u_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); - tcg_temp_free(EA); -} -/*** Floating-point store ***/ -#define GEN_STF(name, stop, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_STUF(name, stop, opc, type) \ -static void glue(gen_, name##u)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - if (unlikely(rA(ctx->opcode) == 0)) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_STUXF(name, stop, opc, type) \ -static void glue(gen_, name##ux)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - if (unlikely(rA(ctx->opcode) == 0)) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_STXF(name, stop, opc2, opc3, type) \ -static void glue(gen_, name##x)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_STFS(name, stop, op, type) \ -GEN_STF(name, stop, op | 0x20, type); \ -GEN_STUF(name, stop, op | 0x21, type); \ -GEN_STUXF(name, stop, op | 0x01, type); \ -GEN_STXF(name, stop, 0x17, op | 0x00, type) - -static inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv t1 = tcg_temp_new(); - gen_helper_float64_to_float32(t0, cpu_env, arg1); - tcg_gen_extu_i32_tl(t1, t0); - tcg_temp_free_i32(t0); - gen_qemu_st32(ctx, t1, arg2); - tcg_temp_free(t1); -} - -/* stfd stfdu stfdux stfdx */ -GEN_STFS(stfd, st64, 0x16, PPC_FLOAT); -/* stfs stfsu stfsux stfsx */ -GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT); - -/* stfdp */ -static void gen_stfdp(DisasContext *ctx) -{ - TCGv EA; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - gen_set_access_type(ctx, ACCESS_FLOAT); - EA = tcg_temp_new(); - gen_addr_imm_index(ctx, EA, 0); - /* We only need to swap high and low halves. gen_qemu_st64 does necessary - 64-bit byteswap already. */ - if (unlikely(ctx->le_mode)) { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); - tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); - } else { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); - tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); - } - tcg_temp_free(EA); -} - -/* stfdpx */ -static void gen_stfdpx(DisasContext *ctx) -{ - TCGv EA; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - gen_set_access_type(ctx, ACCESS_FLOAT); - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - /* We only need to swap high and low halves. gen_qemu_st64 does necessary - 64-bit byteswap already. */ - if (unlikely(ctx->le_mode)) { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); - tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); - } else { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); - tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); - } - tcg_temp_free(EA); -} - -/* Optional: */ -static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) -{ - TCGv t0 = tcg_temp_new(); - tcg_gen_trunc_i64_tl(t0, arg1), - gen_qemu_st32(ctx, t0, arg2); - tcg_temp_free(t0); -} -/* stfiwx */ -GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX); - static inline void gen_update_cfar(DisasContext *ctx, target_ulong nip) { #if defined(TARGET_PPC64) @@ -6176,143 +5239,10 @@ static void gen_rfsvc(DisasContext *ctx) #endif /* defined(CONFIG_USER_ONLY) */ } +#include "translate/fp-impl.c" + /* svc is not implemented for now */ -/* POWER2 specific instructions */ -/* Quad manipulation (load/store two floats at a time) */ - -/* lfq */ -static void gen_lfq(DisasContext *ctx) -{ - int rd = rD(ctx->opcode); - TCGv t0; - gen_set_access_type(ctx, ACCESS_FLOAT); - t0 = tcg_temp_new(); - gen_addr_imm_index(ctx, t0, 0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); - gen_addr_add(ctx, t0, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0); - tcg_temp_free(t0); -} - -/* lfqu */ -static void gen_lfqu(DisasContext *ctx) -{ - int ra = rA(ctx->opcode); - int rd = rD(ctx->opcode); - TCGv t0, t1; - gen_set_access_type(ctx, ACCESS_FLOAT); - t0 = tcg_temp_new(); - t1 = tcg_temp_new(); - gen_addr_imm_index(ctx, t0, 0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); - gen_addr_add(ctx, t1, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1); - if (ra != 0) - tcg_gen_mov_tl(cpu_gpr[ra], t0); - tcg_temp_free(t0); - tcg_temp_free(t1); -} - -/* lfqux */ -static void gen_lfqux(DisasContext *ctx) -{ - int ra = rA(ctx->opcode); - int rd = rD(ctx->opcode); - gen_set_access_type(ctx, ACCESS_FLOAT); - TCGv t0, t1; - t0 = tcg_temp_new(); - gen_addr_reg_index(ctx, t0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); - t1 = tcg_temp_new(); - gen_addr_add(ctx, t1, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1); - tcg_temp_free(t1); - if (ra != 0) - tcg_gen_mov_tl(cpu_gpr[ra], t0); - tcg_temp_free(t0); -} - -/* lfqx */ -static void gen_lfqx(DisasContext *ctx) -{ - int rd = rD(ctx->opcode); - TCGv t0; - gen_set_access_type(ctx, ACCESS_FLOAT); - t0 = tcg_temp_new(); - gen_addr_reg_index(ctx, t0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); - gen_addr_add(ctx, t0, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0); - tcg_temp_free(t0); -} - -/* stfq */ -static void gen_stfq(DisasContext *ctx) -{ - int rd = rD(ctx->opcode); - TCGv t0; - gen_set_access_type(ctx, ACCESS_FLOAT); - t0 = tcg_temp_new(); - gen_addr_imm_index(ctx, t0, 0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); - gen_addr_add(ctx, t0, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0); - tcg_temp_free(t0); -} - -/* stfqu */ -static void gen_stfqu(DisasContext *ctx) -{ - int ra = rA(ctx->opcode); - int rd = rD(ctx->opcode); - TCGv t0, t1; - gen_set_access_type(ctx, ACCESS_FLOAT); - t0 = tcg_temp_new(); - gen_addr_imm_index(ctx, t0, 0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); - t1 = tcg_temp_new(); - gen_addr_add(ctx, t1, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1); - tcg_temp_free(t1); - if (ra != 0) - tcg_gen_mov_tl(cpu_gpr[ra], t0); - tcg_temp_free(t0); -} - -/* stfqux */ -static void gen_stfqux(DisasContext *ctx) -{ - int ra = rA(ctx->opcode); - int rd = rD(ctx->opcode); - TCGv t0, t1; - gen_set_access_type(ctx, ACCESS_FLOAT); - t0 = tcg_temp_new(); - gen_addr_reg_index(ctx, t0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); - t1 = tcg_temp_new(); - gen_addr_add(ctx, t1, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1); - tcg_temp_free(t1); - if (ra != 0) - tcg_gen_mov_tl(cpu_gpr[ra], t0); - tcg_temp_free(t0); -} - -/* stfqx */ -static void gen_stfqx(DisasContext *ctx) -{ - int rd = rD(ctx->opcode); - TCGv t0; - gen_set_access_type(ctx, ACCESS_FLOAT); - t0 = tcg_temp_new(); - gen_addr_reg_index(ctx, t0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); - gen_addr_add(ctx, t0, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0); - tcg_temp_free(t0); -} - /* BookE specific instructions */ /* XXX: not implemented on 440 ? */ @@ -10197,24 +9127,6 @@ GEN_HANDLER2(sradi0, "sradi", 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B), GEN_HANDLER2(sradi1, "sradi", 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B), GEN_HANDLER(srd, 0x1F, 0x1B, 0x10, 0x00000000, PPC_64B), #endif -GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES), -GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT), -GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT), -GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT), -GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT), -GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT), -GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT), -GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT), -GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT), -GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205), -GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207), -GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207), -GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), -GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT), -GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT), -GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT), -GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT), -GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006e0800, PPC_FLOAT), #if defined(TARGET_PPC64) GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B), GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX), @@ -10546,66 +9458,6 @@ GEN_PPC64_R2(rldcr, 0x1E, 0x09), GEN_PPC64_R4(rldimi, 0x1E, 0x06), #endif -#undef _GEN_FLOAT_ACB -#undef GEN_FLOAT_ACB -#undef _GEN_FLOAT_AB -#undef GEN_FLOAT_AB -#undef _GEN_FLOAT_AC -#undef GEN_FLOAT_AC -#undef GEN_FLOAT_B -#undef GEN_FLOAT_BS -#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \ -GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type) -#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \ -_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type), \ -_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type) -#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type) \ -GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) -#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \ -_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type), \ -_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type) -#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type) \ -GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) -#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \ -_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type), \ -_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type) -#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ -GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) -#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \ -GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type) - -GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT), -GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT), -GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT), -GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT), -GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES), -GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE), -_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL), -GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT), -GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT), -GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT), -GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT), -GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT), -GEN_HANDLER_E(ftdiv, 0x3F, 0x00, 0x04, 1, PPC_NONE, PPC2_FP_TST_ISA206), -GEN_HANDLER_E(ftsqrt, 0x3F, 0x00, 0x05, 1, PPC_NONE, PPC2_FP_TST_ISA206), -GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT), -GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT), -GEN_HANDLER_E(fctiwuz, 0x3F, 0x0F, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT), -GEN_HANDLER_E(fcfid, 0x3F, 0x0E, 0x1A, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), -GEN_HANDLER_E(fcfids, 0x3B, 0x0E, 0x1A, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fcfidu, 0x3F, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fcfidus, 0x3B, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fctid, 0x3F, 0x0E, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), -GEN_HANDLER_E(fctidu, 0x3F, 0x0E, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fctidz, 0x3F, 0x0F, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), -GEN_HANDLER_E(fctiduz, 0x3F, 0x0F, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT), -GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT), -GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT), -GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT), - #undef GEN_LD #undef GEN_LDU #undef GEN_LDUX @@ -10679,57 +9531,6 @@ GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST) GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER) GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER) -#undef GEN_LDF -#undef GEN_LDUF -#undef GEN_LDUXF -#undef GEN_LDXF -#undef GEN_LDFS -#define GEN_LDF(name, ldop, opc, type) \ -GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_LDUF(name, ldop, opc, type) \ -GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_LDUXF(name, ldop, opc, type) \ -GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type), -#define GEN_LDXF(name, ldop, opc2, opc3, type) \ -GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type), -#define GEN_LDFS(name, ldop, op, type) \ -GEN_LDF(name, ldop, op | 0x20, type) \ -GEN_LDUF(name, ldop, op | 0x21, type) \ -GEN_LDUXF(name, ldop, op | 0x01, type) \ -GEN_LDXF(name, ldop, 0x17, op | 0x00, type) - -GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT) -GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT) -GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205), -GEN_HANDLER_E(lfiwzx, 0x1f, 0x17, 0x1b, 0x1, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(lfdp, 0x39, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205), -GEN_HANDLER_E(lfdpx, 0x1F, 0x17, 0x18, 0x00200001, PPC_NONE, PPC2_ISA205), - -#undef GEN_STF -#undef GEN_STUF -#undef GEN_STUXF -#undef GEN_STXF -#undef GEN_STFS -#define GEN_STF(name, stop, opc, type) \ -GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_STUF(name, stop, opc, type) \ -GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_STUXF(name, stop, opc, type) \ -GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type), -#define GEN_STXF(name, stop, opc2, opc3, type) \ -GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type), -#define GEN_STFS(name, stop, op, type) \ -GEN_STF(name, stop, op | 0x20, type) \ -GEN_STUF(name, stop, op | 0x21, type) \ -GEN_STUXF(name, stop, op | 0x01, type) \ -GEN_STXF(name, stop, 0x17, op | 0x00, type) - -GEN_STFS(stfd, st64, 0x16, PPC_FLOAT) -GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT) -GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX) -GEN_HANDLER_E(stfdp, 0x3D, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205), -GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205), - #undef GEN_CRLOGIC #define GEN_CRLOGIC(name, tcg_op, opc) \ GEN_HANDLER(name, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) @@ -10788,6 +9589,8 @@ GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00), GEN_MAC_HANDLER(mullhw, 0x08, 0x0D), GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C), +#include "translate/fp-ops.c" + #undef GEN_VR_LDX #undef GEN_VR_STX #undef GEN_VR_LVE diff --git a/target-ppc/translate/fp-impl.c b/target-ppc/translate/fp-impl.c new file mode 100644 index 0000000000..2abc386fcc --- /dev/null +++ b/target-ppc/translate/fp-impl.c @@ -0,0 +1,1098 @@ +/* + * translate-fp.c + * + * Standard FPU translation + */ + +static inline void gen_reset_fpstatus(void) +{ + gen_helper_reset_fpstatus(cpu_env); +} + +static inline void gen_compute_fprf(TCGv_i64 arg) +{ + gen_helper_compute_fprf(cpu_env, arg); + gen_helper_float_check_status(cpu_env); +} + +#if defined(TARGET_PPC64) +static void gen_set_cr1_from_fpscr(DisasContext *ctx) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(tmp, cpu_fpscr); + tcg_gen_shri_i32(cpu_crf[1], tmp, 28); + tcg_temp_free_i32(tmp); +} +#else +static void gen_set_cr1_from_fpscr(DisasContext *ctx) +{ + tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28); +} +#endif + +/*** Floating-Point arithmetic ***/ +#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \ +static void gen_f##name(DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + /* NIP cannot be restored if the memory exception comes from an helper */ \ + gen_update_nip(ctx, ctx->nip - 4); \ + gen_reset_fpstatus(); \ + gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rA(ctx->opcode)], \ + cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \ + if (isfloat) { \ + gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (set_fprf) { \ + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ +} + +#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \ +_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type); \ +_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type); + +#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type) \ +static void gen_f##name(DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + /* NIP cannot be restored if the memory exception comes from an helper */ \ + gen_update_nip(ctx, ctx->nip - 4); \ + gen_reset_fpstatus(); \ + gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rA(ctx->opcode)], \ + cpu_fpr[rB(ctx->opcode)]); \ + if (isfloat) { \ + gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (set_fprf) { \ + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ +} +#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \ +_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ +_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type); + +#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type) \ +static void gen_f##name(DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + /* NIP cannot be restored if the memory exception comes from an helper */ \ + gen_update_nip(ctx, ctx->nip - 4); \ + gen_reset_fpstatus(); \ + gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rA(ctx->opcode)], \ + cpu_fpr[rC(ctx->opcode)]); \ + if (isfloat) { \ + gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (set_fprf) { \ + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ +} +#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \ +_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ +_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type); + +#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ +static void gen_f##name(DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + /* NIP cannot be restored if the memory exception comes from an helper */ \ + gen_update_nip(ctx, ctx->nip - 4); \ + gen_reset_fpstatus(); \ + gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rB(ctx->opcode)]); \ + if (set_fprf) { \ + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ +} + +#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \ +static void gen_f##name(DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + /* NIP cannot be restored if the memory exception comes from an helper */ \ + gen_update_nip(ctx, ctx->nip - 4); \ + gen_reset_fpstatus(); \ + gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rB(ctx->opcode)]); \ + if (set_fprf) { \ + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ +} + +/* fadd - fadds */ +GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT); +/* fdiv - fdivs */ +GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT); +/* fmul - fmuls */ +GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT); + +/* fre */ +GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT); + +/* fres */ +GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES); + +/* frsqrte */ +GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE); + +/* frsqrtes */ +static void gen_frsqrtes(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); + gen_reset_fpstatus(); + gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env, + cpu_fpr[rB(ctx->opcode)]); + gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, + cpu_fpr[rD(ctx->opcode)]); + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_cr1_from_fpscr(ctx); + } +} + +/* fsel */ +_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL); +/* fsub - fsubs */ +GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT); +/* Optional: */ + +/* fsqrt */ +static void gen_fsqrt(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); + gen_reset_fpstatus(); + gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env, + cpu_fpr[rB(ctx->opcode)]); + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_cr1_from_fpscr(ctx); + } +} + +static void gen_fsqrts(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); + gen_reset_fpstatus(); + gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env, + cpu_fpr[rB(ctx->opcode)]); + gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, + cpu_fpr[rD(ctx->opcode)]); + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_cr1_from_fpscr(ctx); + } +} + +/*** Floating-Point multiply-and-add ***/ +/* fmadd - fmadds */ +GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT); +/* fmsub - fmsubs */ +GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT); +/* fnmadd - fnmadds */ +GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT); +/* fnmsub - fnmsubs */ +GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT); + +/*** Floating-Point round & convert ***/ +/* fctiw */ +GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT); +/* fctiwu */ +GEN_FLOAT_B(ctiwu, 0x0E, 0x04, 0, PPC2_FP_CVT_ISA206); +/* fctiwz */ +GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT); +/* fctiwuz */ +GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206); +/* frsp */ +GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT); +/* fcfid */ +GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64); +/* fcfids */ +GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206); +/* fcfidu */ +GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); +/* fcfidus */ +GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); +/* fctid */ +GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64); +/* fctidu */ +GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206); +/* fctidz */ +GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64); +/* fctidu */ +GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206); + +/* frin */ +GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT); +/* friz */ +GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT); +/* frip */ +GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT); +/* frim */ +GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT); + +static void gen_ftdiv(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], + cpu_fpr[rB(ctx->opcode)]); +} + +static void gen_ftsqrt(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); +} + + + +/*** Floating-Point compare ***/ + +/* fcmpo */ +static void gen_fcmpo(DisasContext *ctx) +{ + TCGv_i32 crf; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); + gen_reset_fpstatus(); + crf = tcg_const_i32(crfD(ctx->opcode)); + gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)], + cpu_fpr[rB(ctx->opcode)], crf); + tcg_temp_free_i32(crf); + gen_helper_float_check_status(cpu_env); +} + +/* fcmpu */ +static void gen_fcmpu(DisasContext *ctx) +{ + TCGv_i32 crf; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); + gen_reset_fpstatus(); + crf = tcg_const_i32(crfD(ctx->opcode)); + gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)], + cpu_fpr[rB(ctx->opcode)], crf); + tcg_temp_free_i32(crf); + gen_helper_float_check_status(cpu_env); +} + +/*** Floating-point move ***/ +/* fabs */ +/* XXX: beware that fabs never checks for NaNs nor update FPSCR */ +static void gen_fabs(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + tcg_gen_andi_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], + ~(1ULL << 63)); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } +} + +/* fmr - fmr. */ +/* XXX: beware that fmr never checks for NaNs nor update FPSCR */ +static void gen_fmr(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } +} + +/* fnabs */ +/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */ +static void gen_fnabs(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + tcg_gen_ori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], + 1ULL << 63); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } +} + +/* fneg */ +/* XXX: beware that fneg never checks for NaNs nor update FPSCR */ +static void gen_fneg(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + tcg_gen_xori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], + 1ULL << 63); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } +} + +/* fcpsgn: PowerPC 2.05 specification */ +/* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */ +static void gen_fcpsgn(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], + cpu_fpr[rB(ctx->opcode)], 0, 63); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } +} + +static void gen_fmrgew(DisasContext *ctx) +{ + TCGv_i64 b0; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + b0 = tcg_temp_new_i64(); + tcg_gen_shri_i64(b0, cpu_fpr[rB(ctx->opcode)], 32); + tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], + b0, 0, 32); + tcg_temp_free_i64(b0); +} + +static void gen_fmrgow(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], + cpu_fpr[rB(ctx->opcode)], + cpu_fpr[rA(ctx->opcode)], + 32, 32); +} + +/*** Floating-Point status & ctrl register ***/ + +/* mcrfs */ +static void gen_mcrfs(DisasContext *ctx) +{ + TCGv tmp = tcg_temp_new(); + TCGv_i32 tmask; + TCGv_i64 tnew_fpscr = tcg_temp_new_i64(); + int bfa; + int nibble; + int shift; + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + bfa = crfS(ctx->opcode); + nibble = 7 - bfa; + shift = 4 * nibble; + tcg_gen_shri_tl(tmp, cpu_fpscr, shift); + tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], tmp); + tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], 0xf); + tcg_temp_free(tmp); + tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr); + /* Only the exception bits (including FX) should be cleared if read */ + tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr, ~((0xF << shift) & FP_EX_CLEAR_BITS)); + /* FEX and VX need to be updated, so don't set fpscr directly */ + tmask = tcg_const_i32(1 << nibble); + gen_helper_store_fpscr(cpu_env, tnew_fpscr, tmask); + tcg_temp_free_i32(tmask); + tcg_temp_free_i64(tnew_fpscr); +} + +/* mffs */ +static void gen_mffs(DisasContext *ctx) +{ + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_reset_fpstatus(); + tcg_gen_extu_tl_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } +} + +/* mtfsb0 */ +static void gen_mtfsb0(DisasContext *ctx) +{ + uint8_t crb; + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + crb = 31 - crbD(ctx->opcode); + gen_reset_fpstatus(); + if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) { + TCGv_i32 t0; + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); + t0 = tcg_const_i32(crb); + gen_helper_fpscr_clrbit(cpu_env, t0); + tcg_temp_free_i32(t0); + } + if (unlikely(Rc(ctx->opcode) != 0)) { + tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); + tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); + } +} + +/* mtfsb1 */ +static void gen_mtfsb1(DisasContext *ctx) +{ + uint8_t crb; + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + crb = 31 - crbD(ctx->opcode); + gen_reset_fpstatus(); + /* XXX: we pretend we can only do IEEE floating-point computations */ + if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) { + TCGv_i32 t0; + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); + t0 = tcg_const_i32(crb); + gen_helper_fpscr_setbit(cpu_env, t0); + tcg_temp_free_i32(t0); + } + if (unlikely(Rc(ctx->opcode) != 0)) { + tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); + tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); + } + /* We can raise a differed exception */ + gen_helper_float_check_status(cpu_env); +} + +/* mtfsf */ +static void gen_mtfsf(DisasContext *ctx) +{ + TCGv_i32 t0; + int flm, l, w; + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + flm = FPFLM(ctx->opcode); + l = FPL(ctx->opcode); + w = FPW(ctx->opcode); + if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) { + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); + return; + } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); + gen_reset_fpstatus(); + if (l) { + t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff); + } else { + t0 = tcg_const_i32(flm << (w * 8)); + } + gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0); + tcg_temp_free_i32(t0); + if (unlikely(Rc(ctx->opcode) != 0)) { + tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); + tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); + } + /* We can raise a differed exception */ + gen_helper_float_check_status(cpu_env); +} + +/* mtfsfi */ +static void gen_mtfsfi(DisasContext *ctx) +{ + int bf, sh, w; + TCGv_i64 t0; + TCGv_i32 t1; + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + w = FPW(ctx->opcode); + bf = FPBF(ctx->opcode); + if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) { + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); + return; + } + sh = (8 * w) + 7 - bf; + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); + gen_reset_fpstatus(); + t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh)); + t1 = tcg_const_i32(1 << sh); + gen_helper_store_fpscr(cpu_env, t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i32(t1); + if (unlikely(Rc(ctx->opcode) != 0)) { + tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); + tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); + } + /* We can raise a differed exception */ + gen_helper_float_check_status(cpu_env); +} + +/*** Floating-point load ***/ +#define GEN_LDF(name, ldop, opc, type) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_FLOAT); \ + EA = tcg_temp_new(); \ + gen_addr_imm_index(ctx, EA, 0); \ + gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ +} + +#define GEN_LDUF(name, ldop, opc, type) \ +static void glue(gen_, name##u)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + if (unlikely(rA(ctx->opcode) == 0)) { \ + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_FLOAT); \ + EA = tcg_temp_new(); \ + gen_addr_imm_index(ctx, EA, 0); \ + gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ +} + +#define GEN_LDUXF(name, ldop, opc, type) \ +static void glue(gen_, name##ux)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + if (unlikely(rA(ctx->opcode) == 0)) { \ + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_FLOAT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ +} + +#define GEN_LDXF(name, ldop, opc2, opc3, type) \ +static void glue(gen_, name##x)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_FLOAT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ +} + +#define GEN_LDFS(name, ldop, op, type) \ +GEN_LDF(name, ldop, op | 0x20, type); \ +GEN_LDUF(name, ldop, op | 0x21, type); \ +GEN_LDUXF(name, ldop, op | 0x01, type); \ +GEN_LDXF(name, ldop, 0x17, op | 0x00, type) + +static inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) +{ + TCGv t0 = tcg_temp_new(); + TCGv_i32 t1 = tcg_temp_new_i32(); + gen_qemu_ld32u(ctx, t0, arg2); + tcg_gen_trunc_tl_i32(t1, t0); + tcg_temp_free(t0); + gen_helper_float32_to_float64(arg1, cpu_env, t1); + tcg_temp_free_i32(t1); +} + + /* lfd lfdu lfdux lfdx */ +GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT); + /* lfs lfsu lfsux lfsx */ +GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT); + +/* lfdp */ +static void gen_lfdp(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_set_access_type(ctx, ACCESS_FLOAT); + EA = tcg_temp_new(); + gen_addr_imm_index(ctx, EA, 0); + /* We only need to swap high and low halves. gen_qemu_ld64 does necessary + 64-bit byteswap already. */ + if (unlikely(ctx->le_mode)) { + gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + } else { + gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + } + tcg_temp_free(EA); +} + +/* lfdpx */ +static void gen_lfdpx(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_set_access_type(ctx, ACCESS_FLOAT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + /* We only need to swap high and low halves. gen_qemu_ld64 does necessary + 64-bit byteswap already. */ + if (unlikely(ctx->le_mode)) { + gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + } else { + gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + } + tcg_temp_free(EA); +} + +/* lfiwax */ +static void gen_lfiwax(DisasContext *ctx) +{ + TCGv EA; + TCGv t0; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_set_access_type(ctx, ACCESS_FLOAT); + EA = tcg_temp_new(); + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + gen_qemu_ld32s(ctx, t0, EA); + tcg_gen_ext_tl_i64(cpu_fpr[rD(ctx->opcode)], t0); + tcg_temp_free(EA); + tcg_temp_free(t0); +} + +/* lfiwzx */ +static void gen_lfiwzx(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_set_access_type(ctx, ACCESS_FLOAT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + gen_qemu_ld32u_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + tcg_temp_free(EA); +} +/*** Floating-point store ***/ +#define GEN_STF(name, stop, opc, type) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_FLOAT); \ + EA = tcg_temp_new(); \ + gen_addr_imm_index(ctx, EA, 0); \ + gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ +} + +#define GEN_STUF(name, stop, opc, type) \ +static void glue(gen_, name##u)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + if (unlikely(rA(ctx->opcode) == 0)) { \ + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_FLOAT); \ + EA = tcg_temp_new(); \ + gen_addr_imm_index(ctx, EA, 0); \ + gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ +} + +#define GEN_STUXF(name, stop, opc, type) \ +static void glue(gen_, name##ux)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + if (unlikely(rA(ctx->opcode) == 0)) { \ + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_FLOAT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ + tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ +} + +#define GEN_STXF(name, stop, opc2, opc3, type) \ +static void glue(gen_, name##x)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_FLOAT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ + tcg_temp_free(EA); \ +} + +#define GEN_STFS(name, stop, op, type) \ +GEN_STF(name, stop, op | 0x20, type); \ +GEN_STUF(name, stop, op | 0x21, type); \ +GEN_STUXF(name, stop, op | 0x01, type); \ +GEN_STXF(name, stop, 0x17, op | 0x00, type) + +static inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new(); + gen_helper_float64_to_float32(t0, cpu_env, arg1); + tcg_gen_extu_i32_tl(t1, t0); + tcg_temp_free_i32(t0); + gen_qemu_st32(ctx, t1, arg2); + tcg_temp_free(t1); +} + +/* stfd stfdu stfdux stfdx */ +GEN_STFS(stfd, st64, 0x16, PPC_FLOAT); +/* stfs stfsu stfsux stfsx */ +GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT); + +/* stfdp */ +static void gen_stfdp(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_set_access_type(ctx, ACCESS_FLOAT); + EA = tcg_temp_new(); + gen_addr_imm_index(ctx, EA, 0); + /* We only need to swap high and low halves. gen_qemu_st64 does necessary + 64-bit byteswap already. */ + if (unlikely(ctx->le_mode)) { + gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + } else { + gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + } + tcg_temp_free(EA); +} + +/* stfdpx */ +static void gen_stfdpx(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_set_access_type(ctx, ACCESS_FLOAT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + /* We only need to swap high and low halves. gen_qemu_st64 does necessary + 64-bit byteswap already. */ + if (unlikely(ctx->le_mode)) { + gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + } else { + gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + } + tcg_temp_free(EA); +} + +/* Optional: */ +static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_trunc_i64_tl(t0, arg1), + gen_qemu_st32(ctx, t0, arg2); + tcg_temp_free(t0); +} +/* stfiwx */ +GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX); + +/* POWER2 specific instructions */ +/* Quad manipulation (load/store two floats at a time) */ + +/* lfq */ +static void gen_lfq(DisasContext *ctx) +{ + int rd = rD(ctx->opcode); + TCGv t0; + gen_set_access_type(ctx, ACCESS_FLOAT); + t0 = tcg_temp_new(); + gen_addr_imm_index(ctx, t0, 0); + gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + gen_addr_add(ctx, t0, t0, 8); + gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0); + tcg_temp_free(t0); +} + +/* lfqu */ +static void gen_lfqu(DisasContext *ctx) +{ + int ra = rA(ctx->opcode); + int rd = rD(ctx->opcode); + TCGv t0, t1; + gen_set_access_type(ctx, ACCESS_FLOAT); + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_addr_imm_index(ctx, t0, 0); + gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + gen_addr_add(ctx, t1, t0, 8); + gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1); + if (ra != 0) + tcg_gen_mov_tl(cpu_gpr[ra], t0); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +/* lfqux */ +static void gen_lfqux(DisasContext *ctx) +{ + int ra = rA(ctx->opcode); + int rd = rD(ctx->opcode); + gen_set_access_type(ctx, ACCESS_FLOAT); + TCGv t0, t1; + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, t0); + gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + t1 = tcg_temp_new(); + gen_addr_add(ctx, t1, t0, 8); + gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1); + tcg_temp_free(t1); + if (ra != 0) + tcg_gen_mov_tl(cpu_gpr[ra], t0); + tcg_temp_free(t0); +} + +/* lfqx */ +static void gen_lfqx(DisasContext *ctx) +{ + int rd = rD(ctx->opcode); + TCGv t0; + gen_set_access_type(ctx, ACCESS_FLOAT); + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, t0); + gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + gen_addr_add(ctx, t0, t0, 8); + gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0); + tcg_temp_free(t0); +} + +/* stfq */ +static void gen_stfq(DisasContext *ctx) +{ + int rd = rD(ctx->opcode); + TCGv t0; + gen_set_access_type(ctx, ACCESS_FLOAT); + t0 = tcg_temp_new(); + gen_addr_imm_index(ctx, t0, 0); + gen_qemu_st64(ctx, cpu_fpr[rd], t0); + gen_addr_add(ctx, t0, t0, 8); + gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0); + tcg_temp_free(t0); +} + +/* stfqu */ +static void gen_stfqu(DisasContext *ctx) +{ + int ra = rA(ctx->opcode); + int rd = rD(ctx->opcode); + TCGv t0, t1; + gen_set_access_type(ctx, ACCESS_FLOAT); + t0 = tcg_temp_new(); + gen_addr_imm_index(ctx, t0, 0); + gen_qemu_st64(ctx, cpu_fpr[rd], t0); + t1 = tcg_temp_new(); + gen_addr_add(ctx, t1, t0, 8); + gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1); + tcg_temp_free(t1); + if (ra != 0) + tcg_gen_mov_tl(cpu_gpr[ra], t0); + tcg_temp_free(t0); +} + +/* stfqux */ +static void gen_stfqux(DisasContext *ctx) +{ + int ra = rA(ctx->opcode); + int rd = rD(ctx->opcode); + TCGv t0, t1; + gen_set_access_type(ctx, ACCESS_FLOAT); + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, t0); + gen_qemu_st64(ctx, cpu_fpr[rd], t0); + t1 = tcg_temp_new(); + gen_addr_add(ctx, t1, t0, 8); + gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1); + tcg_temp_free(t1); + if (ra != 0) + tcg_gen_mov_tl(cpu_gpr[ra], t0); + tcg_temp_free(t0); +} + +/* stfqx */ +static void gen_stfqx(DisasContext *ctx) +{ + int rd = rD(ctx->opcode); + TCGv t0; + gen_set_access_type(ctx, ACCESS_FLOAT); + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, t0); + gen_qemu_st64(ctx, cpu_fpr[rd], t0); + gen_addr_add(ctx, t0, t0, 8); + gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0); + tcg_temp_free(t0); +} + +#undef _GEN_FLOAT_ACB +#undef GEN_FLOAT_ACB +#undef _GEN_FLOAT_AB +#undef GEN_FLOAT_AB +#undef _GEN_FLOAT_AC +#undef GEN_FLOAT_AC +#undef GEN_FLOAT_B +#undef GEN_FLOAT_BS + +#undef GEN_LDF +#undef GEN_LDUF +#undef GEN_LDUXF +#undef GEN_LDXF +#undef GEN_LDFS + +#undef GEN_STF +#undef GEN_STUF +#undef GEN_STUXF +#undef GEN_STXF +#undef GEN_STFS diff --git a/target-ppc/translate/fp-ops.c b/target-ppc/translate/fp-ops.c new file mode 100644 index 0000000000..291a1e62d0 --- /dev/null +++ b/target-ppc/translate/fp-ops.c @@ -0,0 +1,111 @@ +#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type) +#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \ +_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type), \ +_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type) +#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) +#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \ +_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type), \ +_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type) +#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) +#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \ +_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type), \ +_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type) +#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ +GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) +#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type) + +GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT), +GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT), +GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT), +GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT), +GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES), +GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE), +_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL), +GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT), +GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT), +GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT), +GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT), +GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT), +GEN_HANDLER_E(ftdiv, 0x3F, 0x00, 0x04, 1, PPC_NONE, PPC2_FP_TST_ISA206), +GEN_HANDLER_E(ftsqrt, 0x3F, 0x00, 0x05, 1, PPC_NONE, PPC2_FP_TST_ISA206), +GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT), +GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206), +GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT), +GEN_HANDLER_E(fctiwuz, 0x3F, 0x0F, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206), +GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT), +GEN_HANDLER_E(fcfid, 0x3F, 0x0E, 0x1A, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), +GEN_HANDLER_E(fcfids, 0x3B, 0x0E, 0x1A, 0, PPC_NONE, PPC2_FP_CVT_ISA206), +GEN_HANDLER_E(fcfidu, 0x3F, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206), +GEN_HANDLER_E(fcfidus, 0x3B, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206), +GEN_HANDLER_E(fctid, 0x3F, 0x0E, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), +GEN_HANDLER_E(fctidu, 0x3F, 0x0E, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206), +GEN_HANDLER_E(fctidz, 0x3F, 0x0F, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), +GEN_HANDLER_E(fctiduz, 0x3F, 0x0F, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206), +GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT), +GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT), +GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT), +GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT), + +#define GEN_LDF(name, ldop, opc, type) \ +GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), +#define GEN_LDUF(name, ldop, opc, type) \ +GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type), +#define GEN_LDUXF(name, ldop, opc, type) \ +GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type), +#define GEN_LDXF(name, ldop, opc2, opc3, type) \ +GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type), +#define GEN_LDFS(name, ldop, op, type) \ +GEN_LDF(name, ldop, op | 0x20, type) \ +GEN_LDUF(name, ldop, op | 0x21, type) \ +GEN_LDUXF(name, ldop, op | 0x01, type) \ +GEN_LDXF(name, ldop, 0x17, op | 0x00, type) + +GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT) +GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT) +GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205), +GEN_HANDLER_E(lfiwzx, 0x1f, 0x17, 0x1b, 0x1, PPC_NONE, PPC2_FP_CVT_ISA206), +GEN_HANDLER_E(lfdp, 0x39, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205), +GEN_HANDLER_E(lfdpx, 0x1F, 0x17, 0x18, 0x00200001, PPC_NONE, PPC2_ISA205), + +#define GEN_STF(name, stop, opc, type) \ +GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), +#define GEN_STUF(name, stop, opc, type) \ +GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type), +#define GEN_STUXF(name, stop, opc, type) \ +GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type), +#define GEN_STXF(name, stop, opc2, opc3, type) \ +GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type), +#define GEN_STFS(name, stop, op, type) \ +GEN_STF(name, stop, op | 0x20, type) \ +GEN_STUF(name, stop, op | 0x21, type) \ +GEN_STUXF(name, stop, op | 0x01, type) \ +GEN_STXF(name, stop, 0x17, op | 0x00, type) + +GEN_STFS(stfd, st64, 0x16, PPC_FLOAT) +GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT) +GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX) +GEN_HANDLER_E(stfdp, 0x3D, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205), +GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205), + +GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES), +GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT), +GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT), +GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT), +GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT), +GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT), +GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT), +GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT), +GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT), +GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205), +GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207), +GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), +GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT), +GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT), +GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT), +GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT), +GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006e0800, PPC_FLOAT), From 4083de6b53a9f5a87cf20ed9465d4956d8169591 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:21 +1000 Subject: [PATCH 18/64] ppc: Move embedded spe ops out of translate.c Makes things a bit more manageable Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate.c | 1328 +------------------------------ target-ppc/translate/spe-impl.c | 1229 ++++++++++++++++++++++++++++ target-ppc/translate/spe-ops.c | 105 +++ 3 files changed, 1336 insertions(+), 1326 deletions(-) create mode 100644 target-ppc/translate/spe-impl.c create mode 100644 target-ppc/translate/spe-ops.c diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 98de1856be..5531d4ec24 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -7765,1226 +7765,7 @@ GEN_DFP_T_FPR_I32_Rc(dscliq, rA, DCM) GEN_DFP_T_FPR_I32_Rc(dscri, rA, DCM) GEN_DFP_T_FPR_I32_Rc(dscriq, rA, DCM) -/*** SPE extension ***/ -/* Register moves */ - -static inline void gen_evmra(DisasContext *ctx) -{ - - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - - TCGv_i64 tmp = tcg_temp_new_i64(); - - /* tmp := rA_lo + rA_hi << 32 */ - tcg_gen_concat_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); - - /* spe_acc := tmp */ - tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); - tcg_temp_free_i64(tmp); - - /* rD := rA */ - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); -} - -static inline void gen_load_gpr64(TCGv_i64 t, int reg) -{ - tcg_gen_concat_tl_i64(t, cpu_gpr[reg], cpu_gprh[reg]); -} - -static inline void gen_store_gpr64(int reg, TCGv_i64 t) -{ - tcg_gen_extr_i64_tl(cpu_gpr[reg], cpu_gprh[reg], t); -} - -#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ -static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ -{ \ - if (Rc(ctx->opcode)) \ - gen_##name1(ctx); \ - else \ - gen_##name0(ctx); \ -} - -/* Handler for undefined SPE opcodes */ -static inline void gen_speundef(DisasContext *ctx) -{ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); -} - -/* SPE logic */ -#define GEN_SPEOP_LOGIC2(name, tcg_op) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], \ - cpu_gpr[rB(ctx->opcode)]); \ - tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], \ - cpu_gprh[rB(ctx->opcode)]); \ -} - -GEN_SPEOP_LOGIC2(evand, tcg_gen_and_tl); -GEN_SPEOP_LOGIC2(evandc, tcg_gen_andc_tl); -GEN_SPEOP_LOGIC2(evxor, tcg_gen_xor_tl); -GEN_SPEOP_LOGIC2(evor, tcg_gen_or_tl); -GEN_SPEOP_LOGIC2(evnor, tcg_gen_nor_tl); -GEN_SPEOP_LOGIC2(eveqv, tcg_gen_eqv_tl); -GEN_SPEOP_LOGIC2(evorc, tcg_gen_orc_tl); -GEN_SPEOP_LOGIC2(evnand, tcg_gen_nand_tl); - -/* SPE logic immediate */ -#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 t0; \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - t0 = tcg_temp_new_i32(); \ - \ - tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ - tcg_opi(t0, t0, rB(ctx->opcode)); \ - tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ - \ - tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]); \ - tcg_opi(t0, t0, rB(ctx->opcode)); \ - tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ - \ - tcg_temp_free_i32(t0); \ -} -GEN_SPEOP_TCG_LOGIC_IMM2(evslwi, tcg_gen_shli_i32); -GEN_SPEOP_TCG_LOGIC_IMM2(evsrwiu, tcg_gen_shri_i32); -GEN_SPEOP_TCG_LOGIC_IMM2(evsrwis, tcg_gen_sari_i32); -GEN_SPEOP_TCG_LOGIC_IMM2(evrlwi, tcg_gen_rotli_i32); - -/* SPE arithmetic */ -#define GEN_SPEOP_ARITH1(name, tcg_op) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 t0; \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - t0 = tcg_temp_new_i32(); \ - \ - tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ - tcg_op(t0, t0); \ - tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ - \ - tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]); \ - tcg_op(t0, t0); \ - tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ - \ - tcg_temp_free_i32(t0); \ -} - -static inline void gen_op_evabs(TCGv_i32 ret, TCGv_i32 arg1) -{ - TCGLabel *l1 = gen_new_label(); - TCGLabel *l2 = gen_new_label(); - - tcg_gen_brcondi_i32(TCG_COND_GE, arg1, 0, l1); - tcg_gen_neg_i32(ret, arg1); - tcg_gen_br(l2); - gen_set_label(l1); - tcg_gen_mov_i32(ret, arg1); - gen_set_label(l2); -} -GEN_SPEOP_ARITH1(evabs, gen_op_evabs); -GEN_SPEOP_ARITH1(evneg, tcg_gen_neg_i32); -GEN_SPEOP_ARITH1(evextsb, tcg_gen_ext8s_i32); -GEN_SPEOP_ARITH1(evextsh, tcg_gen_ext16s_i32); -static inline void gen_op_evrndw(TCGv_i32 ret, TCGv_i32 arg1) -{ - tcg_gen_addi_i32(ret, arg1, 0x8000); - tcg_gen_ext16u_i32(ret, ret); -} -GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw); -GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32); -GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32); - -#define GEN_SPEOP_ARITH2(name, tcg_op) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 t0, t1; \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - t0 = tcg_temp_new_i32(); \ - t1 = tcg_temp_new_i32(); \ - \ - tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ - tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - tcg_op(t0, t0, t1); \ - tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ - \ - tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]); \ - tcg_gen_trunc_tl_i32(t1, cpu_gprh[rB(ctx->opcode)]); \ - tcg_op(t0, t0, t1); \ - tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ - \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_i32(t1); \ -} - -static inline void gen_op_evsrwu(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) -{ - TCGLabel *l1 = gen_new_label(); - TCGLabel *l2 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_local_new_i32(); - - /* No error here: 6 bits are used */ - tcg_gen_andi_i32(t0, arg2, 0x3F); - tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1); - tcg_gen_shr_i32(ret, arg1, t0); - tcg_gen_br(l2); - gen_set_label(l1); - tcg_gen_movi_i32(ret, 0); - gen_set_label(l2); - tcg_temp_free_i32(t0); -} -GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu); -static inline void gen_op_evsrws(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) -{ - TCGLabel *l1 = gen_new_label(); - TCGLabel *l2 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_local_new_i32(); - - /* No error here: 6 bits are used */ - tcg_gen_andi_i32(t0, arg2, 0x3F); - tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1); - tcg_gen_sar_i32(ret, arg1, t0); - tcg_gen_br(l2); - gen_set_label(l1); - tcg_gen_movi_i32(ret, 0); - gen_set_label(l2); - tcg_temp_free_i32(t0); -} -GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws); -static inline void gen_op_evslw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) -{ - TCGLabel *l1 = gen_new_label(); - TCGLabel *l2 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_local_new_i32(); - - /* No error here: 6 bits are used */ - tcg_gen_andi_i32(t0, arg2, 0x3F); - tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1); - tcg_gen_shl_i32(ret, arg1, t0); - tcg_gen_br(l2); - gen_set_label(l1); - tcg_gen_movi_i32(ret, 0); - gen_set_label(l2); - tcg_temp_free_i32(t0); -} -GEN_SPEOP_ARITH2(evslw, gen_op_evslw); -static inline void gen_op_evrlw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - tcg_gen_andi_i32(t0, arg2, 0x1F); - tcg_gen_rotl_i32(ret, arg1, t0); - tcg_temp_free_i32(t0); -} -GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw); -static inline void gen_evmergehi(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); -} -GEN_SPEOP_ARITH2(evaddw, tcg_gen_add_i32); -static inline void gen_op_evsubf(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) -{ - tcg_gen_sub_i32(ret, arg2, arg1); -} -GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf); - -/* SPE arithmetic immediate */ -#define GEN_SPEOP_ARITH_IMM2(name, tcg_op) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 t0; \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - t0 = tcg_temp_new_i32(); \ - \ - tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ - tcg_op(t0, t0, rA(ctx->opcode)); \ - tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ - \ - tcg_gen_trunc_tl_i32(t0, cpu_gprh[rB(ctx->opcode)]); \ - tcg_op(t0, t0, rA(ctx->opcode)); \ - tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ - \ - tcg_temp_free_i32(t0); \ -} -GEN_SPEOP_ARITH_IMM2(evaddiw, tcg_gen_addi_i32); -GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32); - -/* SPE comparison */ -#define GEN_SPEOP_COMP(name, tcg_cond) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - TCGLabel *l1 = gen_new_label(); \ - TCGLabel *l2 = gen_new_label(); \ - TCGLabel *l3 = gen_new_label(); \ - TCGLabel *l4 = gen_new_label(); \ - \ - tcg_gen_ext32s_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); \ - tcg_gen_ext32s_tl(cpu_gpr[rB(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ - tcg_gen_ext32s_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); \ - tcg_gen_ext32s_tl(cpu_gprh[rB(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); \ - \ - tcg_gen_brcond_tl(tcg_cond, cpu_gpr[rA(ctx->opcode)], \ - cpu_gpr[rB(ctx->opcode)], l1); \ - tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0); \ - tcg_gen_br(l2); \ - gen_set_label(l1); \ - tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], \ - CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL); \ - gen_set_label(l2); \ - tcg_gen_brcond_tl(tcg_cond, cpu_gprh[rA(ctx->opcode)], \ - cpu_gprh[rB(ctx->opcode)], l3); \ - tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], \ - ~(CRF_CH | CRF_CH_AND_CL)); \ - tcg_gen_br(l4); \ - gen_set_label(l3); \ - tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], \ - CRF_CH | CRF_CH_OR_CL); \ - gen_set_label(l4); \ -} -GEN_SPEOP_COMP(evcmpgtu, TCG_COND_GTU); -GEN_SPEOP_COMP(evcmpgts, TCG_COND_GT); -GEN_SPEOP_COMP(evcmpltu, TCG_COND_LTU); -GEN_SPEOP_COMP(evcmplts, TCG_COND_LT); -GEN_SPEOP_COMP(evcmpeq, TCG_COND_EQ); - -/* SPE misc */ -static inline void gen_brinc(DisasContext *ctx) -{ - /* Note: brinc is usable even if SPE is disabled */ - gen_helper_brinc(cpu_gpr[rD(ctx->opcode)], - cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); -} -static inline void gen_evmergelo(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); -} -static inline void gen_evmergehilo(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); -} -static inline void gen_evmergelohi(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - if (rD(ctx->opcode) == rA(ctx->opcode)) { - TCGv tmp = tcg_temp_new(); - tcg_gen_mov_tl(tmp, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], tmp); - tcg_temp_free(tmp); - } else { - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - } -} -static inline void gen_evsplati(DisasContext *ctx) -{ - uint64_t imm = ((int32_t)(rA(ctx->opcode) << 27)) >> 27; - - tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], imm); - tcg_gen_movi_tl(cpu_gprh[rD(ctx->opcode)], imm); -} -static inline void gen_evsplatfi(DisasContext *ctx) -{ - uint64_t imm = rA(ctx->opcode) << 27; - - tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], imm); - tcg_gen_movi_tl(cpu_gprh[rD(ctx->opcode)], imm); -} - -static inline void gen_evsel(DisasContext *ctx) -{ - TCGLabel *l1 = gen_new_label(); - TCGLabel *l2 = gen_new_label(); - TCGLabel *l3 = gen_new_label(); - TCGLabel *l4 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_local_new_i32(); - - tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 3); - tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); - tcg_gen_br(l2); - gen_set_label(l1); - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); - gen_set_label(l2); - tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 2); - tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l3); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_br(l4); - gen_set_label(l3); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); - gen_set_label(l4); - tcg_temp_free_i32(t0); -} - -static void gen_evsel0(DisasContext *ctx) -{ - gen_evsel(ctx); -} - -static void gen_evsel1(DisasContext *ctx) -{ - gen_evsel(ctx); -} - -static void gen_evsel2(DisasContext *ctx) -{ - gen_evsel(ctx); -} - -static void gen_evsel3(DisasContext *ctx) -{ - gen_evsel(ctx); -} - -/* Multiply */ - -static inline void gen_evmwumi(DisasContext *ctx) -{ - TCGv_i64 t0, t1; - - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - - /* t0 := rA; t1 := rB */ - tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ext32u_i64(t0, t0); - tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); - tcg_gen_ext32u_i64(t1, t1); - - tcg_gen_mul_i64(t0, t0, t1); /* t0 := rA * rB */ - - gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */ - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); -} - -static inline void gen_evmwumia(DisasContext *ctx) -{ - TCGv_i64 tmp; - - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - - gen_evmwumi(ctx); /* rD := rA * rB */ - - tmp = tcg_temp_new_i64(); - - /* acc := rD */ - gen_load_gpr64(tmp, rD(ctx->opcode)); - tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); - tcg_temp_free_i64(tmp); -} - -static inline void gen_evmwumiaa(DisasContext *ctx) -{ - TCGv_i64 acc; - TCGv_i64 tmp; - - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - - gen_evmwumi(ctx); /* rD := rA * rB */ - - acc = tcg_temp_new_i64(); - tmp = tcg_temp_new_i64(); - - /* tmp := rD */ - gen_load_gpr64(tmp, rD(ctx->opcode)); - - /* Load acc */ - tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); - - /* acc := tmp + acc */ - tcg_gen_add_i64(acc, acc, tmp); - - /* Store acc */ - tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); - - /* rD := acc */ - gen_store_gpr64(rD(ctx->opcode), acc); - - tcg_temp_free_i64(acc); - tcg_temp_free_i64(tmp); -} - -static inline void gen_evmwsmi(DisasContext *ctx) -{ - TCGv_i64 t0, t1; - - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - - /* t0 := rA; t1 := rB */ - tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ext32s_i64(t0, t0); - tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); - tcg_gen_ext32s_i64(t1, t1); - - tcg_gen_mul_i64(t0, t0, t1); /* t0 := rA * rB */ - - gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */ - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); -} - -static inline void gen_evmwsmia(DisasContext *ctx) -{ - TCGv_i64 tmp; - - gen_evmwsmi(ctx); /* rD := rA * rB */ - - tmp = tcg_temp_new_i64(); - - /* acc := rD */ - gen_load_gpr64(tmp, rD(ctx->opcode)); - tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); - - tcg_temp_free_i64(tmp); -} - -static inline void gen_evmwsmiaa(DisasContext *ctx) -{ - TCGv_i64 acc = tcg_temp_new_i64(); - TCGv_i64 tmp = tcg_temp_new_i64(); - - gen_evmwsmi(ctx); /* rD := rA * rB */ - - acc = tcg_temp_new_i64(); - tmp = tcg_temp_new_i64(); - - /* tmp := rD */ - gen_load_gpr64(tmp, rD(ctx->opcode)); - - /* Load acc */ - tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); - - /* acc := tmp + acc */ - tcg_gen_add_i64(acc, acc, tmp); - - /* Store acc */ - tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); - - /* rD := acc */ - gen_store_gpr64(rD(ctx->opcode), acc); - - tcg_temp_free_i64(acc); - tcg_temp_free_i64(tmp); -} - -GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// -GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); -GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// -GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); -GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// -GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// -GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// -GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE); // -GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE); -GEN_SPE(speundef, evand, 0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); //// -GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// -GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// -GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// -GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evorc, 0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); //// -GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// -GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// -GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// -GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); -GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE); // -GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE); -GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// -GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// -GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE); //// -GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE); //// -GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE); //// - -/* SPE load and stores */ -static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh) -{ - target_ulong uimm = rB(ctx->opcode); - - if (rA(ctx->opcode) == 0) { - tcg_gen_movi_tl(EA, uimm << sh); - } else { - tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh); - if (NARROW_MODE(ctx)) { - tcg_gen_ext32u_tl(EA, EA); - } - } -} - -static inline void gen_op_evldd(DisasContext *ctx, TCGv addr) -{ - TCGv_i64 t0 = tcg_temp_new_i64(); - gen_qemu_ld64(ctx, t0, addr); - gen_store_gpr64(rD(ctx->opcode), t0); - tcg_temp_free_i64(t0); -} - -static inline void gen_op_evldw(DisasContext *ctx, TCGv addr) -{ - gen_qemu_ld32u(ctx, cpu_gprh[rD(ctx->opcode)], addr); - gen_addr_add(ctx, addr, addr, 4); - gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], addr); -} - -static inline void gen_op_evldh(DisasContext *ctx, TCGv addr) -{ - TCGv t0 = tcg_temp_new(); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); -} - -static inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr) -{ - TCGv t0 = tcg_temp_new(); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(t0, t0, 16); - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); -} - -static inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr) -{ - TCGv t0 = tcg_temp_new(); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); -} - -static inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr) -{ - TCGv t0 = tcg_temp_new(); - gen_qemu_ld16s(ctx, t0, addr); - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); -} - -static inline void gen_op_evlwhe(DisasContext *ctx, TCGv addr) -{ - TCGv t0 = tcg_temp_new(); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16); - tcg_temp_free(t0); -} - -static inline void gen_op_evlwhou(DisasContext *ctx, TCGv addr) -{ - gen_qemu_ld16u(ctx, cpu_gprh[rD(ctx->opcode)], addr); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr); -} - -static inline void gen_op_evlwhos(DisasContext *ctx, TCGv addr) -{ - gen_qemu_ld16s(ctx, cpu_gprh[rD(ctx->opcode)], addr); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16s(ctx, cpu_gpr[rD(ctx->opcode)], addr); -} - -static inline void gen_op_evlwwsplat(DisasContext *ctx, TCGv addr) -{ - TCGv t0 = tcg_temp_new(); - gen_qemu_ld32u(ctx, t0, addr); - tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); -} - -static inline void gen_op_evlwhsplat(DisasContext *ctx, TCGv addr) -{ - TCGv t0 = tcg_temp_new(); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16); - tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0); - tcg_temp_free(t0); -} - -static inline void gen_op_evstdd(DisasContext *ctx, TCGv addr) -{ - TCGv_i64 t0 = tcg_temp_new_i64(); - gen_load_gpr64(t0, rS(ctx->opcode)); - gen_qemu_st64(ctx, t0, addr); - tcg_temp_free_i64(t0); -} - -static inline void gen_op_evstdw(DisasContext *ctx, TCGv addr) -{ - gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr); - gen_addr_add(ctx, addr, addr, 4); - gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr); -} - -static inline void gen_op_evstdh(DisasContext *ctx, TCGv addr) -{ - TCGv t0 = tcg_temp_new(); - tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16); - gen_qemu_st16(ctx, t0, addr); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr); - gen_addr_add(ctx, addr, addr, 2); - tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16); - gen_qemu_st16(ctx, t0, addr); - tcg_temp_free(t0); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr); -} - -static inline void gen_op_evstwhe(DisasContext *ctx, TCGv addr) -{ - TCGv t0 = tcg_temp_new(); - tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16); - gen_qemu_st16(ctx, t0, addr); - gen_addr_add(ctx, addr, addr, 2); - tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16); - gen_qemu_st16(ctx, t0, addr); - tcg_temp_free(t0); -} - -static inline void gen_op_evstwho(DisasContext *ctx, TCGv addr) -{ - gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr); -} - -static inline void gen_op_evstwwe(DisasContext *ctx, TCGv addr) -{ - gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr); -} - -static inline void gen_op_evstwwo(DisasContext *ctx, TCGv addr) -{ - gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr); -} - -#define GEN_SPEOP_LDST(name, opc2, sh) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv t0; \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_INT); \ - t0 = tcg_temp_new(); \ - if (Rc(ctx->opcode)) { \ - gen_addr_spe_imm_index(ctx, t0, sh); \ - } else { \ - gen_addr_reg_index(ctx, t0); \ - } \ - gen_op_##name(ctx, t0); \ - tcg_temp_free(t0); \ -} - -GEN_SPEOP_LDST(evldd, 0x00, 3); -GEN_SPEOP_LDST(evldw, 0x01, 3); -GEN_SPEOP_LDST(evldh, 0x02, 3); -GEN_SPEOP_LDST(evlhhesplat, 0x04, 1); -GEN_SPEOP_LDST(evlhhousplat, 0x06, 1); -GEN_SPEOP_LDST(evlhhossplat, 0x07, 1); -GEN_SPEOP_LDST(evlwhe, 0x08, 2); -GEN_SPEOP_LDST(evlwhou, 0x0A, 2); -GEN_SPEOP_LDST(evlwhos, 0x0B, 2); -GEN_SPEOP_LDST(evlwwsplat, 0x0C, 2); -GEN_SPEOP_LDST(evlwhsplat, 0x0E, 2); - -GEN_SPEOP_LDST(evstdd, 0x10, 3); -GEN_SPEOP_LDST(evstdw, 0x11, 3); -GEN_SPEOP_LDST(evstdh, 0x12, 3); -GEN_SPEOP_LDST(evstwhe, 0x18, 2); -GEN_SPEOP_LDST(evstwho, 0x1A, 2); -GEN_SPEOP_LDST(evstwwe, 0x1C, 2); -GEN_SPEOP_LDST(evstwwo, 0x1E, 2); - -/* Multiply and add - TODO */ -#if 0 -GEN_SPE(speundef, evmhessf, 0x01, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);// -GEN_SPE(speundef, evmhossf, 0x03, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmheumi, evmhesmi, 0x04, 0x10, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmf, 0x05, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumi, evmhosmi, 0x06, 0x10, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmf, 0x07, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhessfa, 0x11, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhossfa, 0x13, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmheumia, evmhesmia, 0x14, 0x10, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmfa, 0x15, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumia, evmhosmia, 0x16, 0x10, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmfa, 0x17, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); - -GEN_SPE(speundef, evmwhssf, 0x03, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumi, speundef, 0x04, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE); -GEN_SPE(evmwhumi, evmwhsmi, 0x06, 0x11, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwhsmf, 0x07, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssf, 0x09, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmf, 0x0D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwhssfa, 0x13, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumia, speundef, 0x14, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE); -GEN_SPE(evmwhumia, evmwhsmia, 0x16, 0x11, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwhsmfa, 0x17, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssfa, 0x19, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmfa, 0x1D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); - -GEN_SPE(evadduiaaw, evaddsiaaw, 0x00, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); -GEN_SPE(evsubfusiaaw, evsubfssiaaw, 0x01, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); -GEN_SPE(evaddumiaaw, evaddsmiaaw, 0x04, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); -GEN_SPE(evsubfumiaaw, evsubfsmiaaw, 0x05, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); -GEN_SPE(evdivws, evdivwu, 0x06, 0x13, 0x00000000, 0x00000000, PPC_SPE); - -GEN_SPE(evmheusiaaw, evmhessiaaw, 0x00, 0x14, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhessfaaw, 0x01, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmhousiaaw, evmhossiaaw, 0x02, 0x14, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhossfaaw, 0x03, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmheumiaaw, evmhesmiaaw, 0x04, 0x14, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmfaaw, 0x05, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumiaaw, evmhosmiaaw, 0x06, 0x14, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmfaaw, 0x07, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmhegumiaa, evmhegsmiaa, 0x14, 0x14, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhegsmfaa, 0x15, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmhogumiaa, evmhogsmiaa, 0x16, 0x14, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhogsmfaa, 0x17, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); - -GEN_SPE(evmwlusiaaw, evmwlssiaaw, 0x00, 0x15, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumiaaw, evmwlsmiaaw, 0x04, 0x15, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssfaa, 0x09, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmfaa, 0x0D, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE); - -GEN_SPE(evmheusianw, evmhessianw, 0x00, 0x16, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhessfanw, 0x01, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmhousianw, evmhossianw, 0x02, 0x16, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhossfanw, 0x03, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmheumianw, evmhesmianw, 0x04, 0x16, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhesmfanw, 0x05, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmhoumianw, evmhosmianw, 0x06, 0x16, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhosmfanw, 0x07, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmhegumian, evmhegsmian, 0x14, 0x16, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhegsmfan, 0x15, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmhigumian, evmhigsmian, 0x16, 0x16, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmhogsmfan, 0x17, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); - -GEN_SPE(evmwlusianw, evmwlssianw, 0x00, 0x17, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(evmwlumianw, evmwlsmianw, 0x04, 0x17, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwssfan, 0x09, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE); -GEN_SPE(evmwumian, evmwsmian, 0x0C, 0x17, 0x00000000, 0x00000000, PPC_SPE); -GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE); -#endif - -/*** SPE floating-point extension ***/ -#define GEN_SPEFPUOP_CONV_32_32(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 t0 = tcg_temp_new_i32(); \ - tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, cpu_env, t0); \ - tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ - tcg_temp_free_i32(t0); \ -} -#define GEN_SPEFPUOP_CONV_32_64(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i64 t0 = tcg_temp_new_i64(); \ - TCGv_i32 t1 = tcg_temp_new_i32(); \ - gen_load_gpr64(t0, rB(ctx->opcode)); \ - gen_helper_##name(t1, cpu_env, t0); \ - tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1); \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i32(t1); \ -} -#define GEN_SPEFPUOP_CONV_64_32(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i64 t0 = tcg_temp_new_i64(); \ - TCGv_i32 t1 = tcg_temp_new_i32(); \ - tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, cpu_env, t1); \ - gen_store_gpr64(rD(ctx->opcode), t0); \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i32(t1); \ -} -#define GEN_SPEFPUOP_CONV_64_64(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i64 t0 = tcg_temp_new_i64(); \ - gen_load_gpr64(t0, rB(ctx->opcode)); \ - gen_helper_##name(t0, cpu_env, t0); \ - gen_store_gpr64(rD(ctx->opcode), t0); \ - tcg_temp_free_i64(t0); \ -} -#define GEN_SPEFPUOP_ARITH2_32_32(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 t0, t1; \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - t0 = tcg_temp_new_i32(); \ - t1 = tcg_temp_new_i32(); \ - tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ - tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, cpu_env, t0, t1); \ - tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ - \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_i32(t1); \ -} -#define GEN_SPEFPUOP_ARITH2_64_64(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i64 t0, t1; \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - t0 = tcg_temp_new_i64(); \ - t1 = tcg_temp_new_i64(); \ - gen_load_gpr64(t0, rA(ctx->opcode)); \ - gen_load_gpr64(t1, rB(ctx->opcode)); \ - gen_helper_##name(t0, cpu_env, t0, t1); \ - gen_store_gpr64(rD(ctx->opcode), t0); \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i64(t1); \ -} -#define GEN_SPEFPUOP_COMP_32(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 t0, t1; \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - t0 = tcg_temp_new_i32(); \ - t1 = tcg_temp_new_i32(); \ - \ - tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ - tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ - \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_i32(t1); \ -} -#define GEN_SPEFPUOP_COMP_64(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i64 t0, t1; \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - t0 = tcg_temp_new_i64(); \ - t1 = tcg_temp_new_i64(); \ - gen_load_gpr64(t0, rA(ctx->opcode)); \ - gen_load_gpr64(t1, rB(ctx->opcode)); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i64(t1); \ -} - -/* Single precision floating-point vectors operations */ -/* Arithmetic */ -GEN_SPEFPUOP_ARITH2_64_64(evfsadd); -GEN_SPEFPUOP_ARITH2_64_64(evfssub); -GEN_SPEFPUOP_ARITH2_64_64(evfsmul); -GEN_SPEFPUOP_ARITH2_64_64(evfsdiv); -static inline void gen_evfsabs(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], - ~0x80000000); - tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], - ~0x80000000); -} -static inline void gen_evfsnabs(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], - 0x80000000); - tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], - 0x80000000); -} -static inline void gen_evfsneg(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], - 0x80000000); - tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], - 0x80000000); -} - -/* Conversion */ -GEN_SPEFPUOP_CONV_64_64(evfscfui); -GEN_SPEFPUOP_CONV_64_64(evfscfsi); -GEN_SPEFPUOP_CONV_64_64(evfscfuf); -GEN_SPEFPUOP_CONV_64_64(evfscfsf); -GEN_SPEFPUOP_CONV_64_64(evfsctui); -GEN_SPEFPUOP_CONV_64_64(evfsctsi); -GEN_SPEFPUOP_CONV_64_64(evfsctuf); -GEN_SPEFPUOP_CONV_64_64(evfsctsf); -GEN_SPEFPUOP_CONV_64_64(evfsctuiz); -GEN_SPEFPUOP_CONV_64_64(evfsctsiz); - -/* Comparison */ -GEN_SPEFPUOP_COMP_64(evfscmpgt); -GEN_SPEFPUOP_COMP_64(evfscmplt); -GEN_SPEFPUOP_COMP_64(evfscmpeq); -GEN_SPEFPUOP_COMP_64(evfststgt); -GEN_SPEFPUOP_COMP_64(evfststlt); -GEN_SPEFPUOP_COMP_64(evfststeq); - -/* Opcodes definitions */ -GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); // -GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // -GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // -GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // -GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // - -/* Single precision floating-point operations */ -/* Arithmetic */ -GEN_SPEFPUOP_ARITH2_32_32(efsadd); -GEN_SPEFPUOP_ARITH2_32_32(efssub); -GEN_SPEFPUOP_ARITH2_32_32(efsmul); -GEN_SPEFPUOP_ARITH2_32_32(efsdiv); -static inline void gen_efsabs(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL); -} -static inline void gen_efsnabs(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); -} -static inline void gen_efsneg(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); -} - -/* Conversion */ -GEN_SPEFPUOP_CONV_32_32(efscfui); -GEN_SPEFPUOP_CONV_32_32(efscfsi); -GEN_SPEFPUOP_CONV_32_32(efscfuf); -GEN_SPEFPUOP_CONV_32_32(efscfsf); -GEN_SPEFPUOP_CONV_32_32(efsctui); -GEN_SPEFPUOP_CONV_32_32(efsctsi); -GEN_SPEFPUOP_CONV_32_32(efsctuf); -GEN_SPEFPUOP_CONV_32_32(efsctsf); -GEN_SPEFPUOP_CONV_32_32(efsctuiz); -GEN_SPEFPUOP_CONV_32_32(efsctsiz); -GEN_SPEFPUOP_CONV_32_64(efscfd); - -/* Comparison */ -GEN_SPEFPUOP_COMP_32(efscmpgt); -GEN_SPEFPUOP_COMP_32(efscmplt); -GEN_SPEFPUOP_COMP_32(efscmpeq); -GEN_SPEFPUOP_COMP_32(efststgt); -GEN_SPEFPUOP_COMP_32(efststlt); -GEN_SPEFPUOP_COMP_32(efststeq); - -/* Opcodes definitions */ -GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); // -GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // -GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // -GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // - -/* Double precision floating-point operations */ -/* Arithmetic */ -GEN_SPEFPUOP_ARITH2_64_64(efdadd); -GEN_SPEFPUOP_ARITH2_64_64(efdsub); -GEN_SPEFPUOP_ARITH2_64_64(efdmul); -GEN_SPEFPUOP_ARITH2_64_64(efddiv); -static inline void gen_efdabs(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], - ~0x80000000); -} -static inline void gen_efdnabs(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], - 0x80000000); -} -static inline void gen_efdneg(DisasContext *ctx) -{ - if (unlikely(!ctx->spe_enabled)) { - gen_exception(ctx, POWERPC_EXCP_SPEU); - return; - } - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], - 0x80000000); -} - -/* Conversion */ -GEN_SPEFPUOP_CONV_64_32(efdcfui); -GEN_SPEFPUOP_CONV_64_32(efdcfsi); -GEN_SPEFPUOP_CONV_64_32(efdcfuf); -GEN_SPEFPUOP_CONV_64_32(efdcfsf); -GEN_SPEFPUOP_CONV_32_64(efdctui); -GEN_SPEFPUOP_CONV_32_64(efdctsi); -GEN_SPEFPUOP_CONV_32_64(efdctuf); -GEN_SPEFPUOP_CONV_32_64(efdctsf); -GEN_SPEFPUOP_CONV_32_64(efdctuiz); -GEN_SPEFPUOP_CONV_32_64(efdctsiz); -GEN_SPEFPUOP_CONV_64_32(efdcfs); -GEN_SPEFPUOP_CONV_64_64(efdcfuid); -GEN_SPEFPUOP_CONV_64_64(efdcfsid); -GEN_SPEFPUOP_CONV_64_64(efdctuidz); -GEN_SPEFPUOP_CONV_64_64(efdctsidz); - -/* Comparison */ -GEN_SPEFPUOP_COMP_64(efdcmpgt); -GEN_SPEFPUOP_COMP_64(efdcmplt); -GEN_SPEFPUOP_COMP_64(efdcmpeq); -GEN_SPEFPUOP_COMP_64(efdtstgt); -GEN_SPEFPUOP_COMP_64(efdtstlt); -GEN_SPEFPUOP_COMP_64(efdtsteq); - -/* Opcodes definitions */ -GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE); // -GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE); // -GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // -GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // -GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // -GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +#include "translate/spe-impl.c" static void gen_tbegin(DisasContext *ctx) { @@ -9338,10 +8119,6 @@ GEN_HANDLER_E(maddhd_maddhdu, 0x04, 0x18, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(maddld, 0x04, 0x19, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300), #endif -GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE), -GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE), -GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE), -GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE), #undef GEN_INT_ARITH_ADD #undef GEN_INT_ARITH_ADD_CONST @@ -10289,108 +9066,7 @@ GEN_DFP_Tp_Ap_SH_Rc(dscliq, 0x02, 0x02), GEN_DFP_T_A_SH_Rc(dscri, 0x02, 0x03), GEN_DFP_Tp_Ap_SH_Rc(dscriq, 0x02, 0x03), -#undef GEN_SPE -#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ - GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE) -GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), -GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), -GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), -GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), -GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), -GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), -GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), -GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE), -GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE), -GEN_SPE(speundef, evand, 0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE), -GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), -GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE), -GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE), -GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE), -GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE), -GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE), -GEN_SPE(speundef, evorc, 0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE), -GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), -GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE), -GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE), -GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), -GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), -GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE), -GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE), -GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE), -GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE), -GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE), -GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE), -GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE), - -GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE), -GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), -GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), -GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), -GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), - -GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE), -GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), -GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), -GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), - -GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE), -GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE), -GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE), -GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE), -GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE), -GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE), -GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE), - -#undef GEN_SPEOP_LDST -#define GEN_SPEOP_LDST(name, opc2, sh) \ -GEN_HANDLER(name, 0x04, opc2, 0x0C, 0x00000000, PPC_SPE) -GEN_SPEOP_LDST(evldd, 0x00, 3), -GEN_SPEOP_LDST(evldw, 0x01, 3), -GEN_SPEOP_LDST(evldh, 0x02, 3), -GEN_SPEOP_LDST(evlhhesplat, 0x04, 1), -GEN_SPEOP_LDST(evlhhousplat, 0x06, 1), -GEN_SPEOP_LDST(evlhhossplat, 0x07, 1), -GEN_SPEOP_LDST(evlwhe, 0x08, 2), -GEN_SPEOP_LDST(evlwhou, 0x0A, 2), -GEN_SPEOP_LDST(evlwhos, 0x0B, 2), -GEN_SPEOP_LDST(evlwwsplat, 0x0C, 2), -GEN_SPEOP_LDST(evlwhsplat, 0x0E, 2), - -GEN_SPEOP_LDST(evstdd, 0x10, 3), -GEN_SPEOP_LDST(evstdw, 0x11, 3), -GEN_SPEOP_LDST(evstdh, 0x12, 3), -GEN_SPEOP_LDST(evstwhe, 0x18, 2), -GEN_SPEOP_LDST(evstwho, 0x1A, 2), -GEN_SPEOP_LDST(evstwwe, 0x1C, 2), -GEN_SPEOP_LDST(evstwwo, 0x1E, 2), +#include "translate/spe-ops.c" GEN_HANDLER2_E(tbegin, "tbegin", 0x1F, 0x0E, 0x14, 0x01DFF800, \ PPC_NONE, PPC2_TM), diff --git a/target-ppc/translate/spe-impl.c b/target-ppc/translate/spe-impl.c new file mode 100644 index 0000000000..0ce403a861 --- /dev/null +++ b/target-ppc/translate/spe-impl.c @@ -0,0 +1,1229 @@ +/* + * translate-spe.c + * + * Freescale SPE extension translation + */ + +/*** SPE extension ***/ +/* Register moves */ + +static inline void gen_evmra(DisasContext *ctx) +{ + + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + + TCGv_i64 tmp = tcg_temp_new_i64(); + + /* tmp := rA_lo + rA_hi << 32 */ + tcg_gen_concat_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); + + /* spe_acc := tmp */ + tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_temp_free_i64(tmp); + + /* rD := rA */ + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); +} + +static inline void gen_load_gpr64(TCGv_i64 t, int reg) +{ + tcg_gen_concat_tl_i64(t, cpu_gpr[reg], cpu_gprh[reg]); +} + +static inline void gen_store_gpr64(int reg, TCGv_i64 t) +{ + tcg_gen_extr_i64_tl(cpu_gpr[reg], cpu_gprh[reg], t); +} + +#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ +static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ +{ \ + if (Rc(ctx->opcode)) \ + gen_##name1(ctx); \ + else \ + gen_##name0(ctx); \ +} + +/* Handler for undefined SPE opcodes */ +static inline void gen_speundef(DisasContext *ctx) +{ + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); +} + +/* SPE logic */ +#define GEN_SPEOP_LOGIC2(name, tcg_op) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_SPEU); \ + return; \ + } \ + tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], \ + cpu_gpr[rB(ctx->opcode)]); \ + tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], \ + cpu_gprh[rB(ctx->opcode)]); \ +} + +GEN_SPEOP_LOGIC2(evand, tcg_gen_and_tl); +GEN_SPEOP_LOGIC2(evandc, tcg_gen_andc_tl); +GEN_SPEOP_LOGIC2(evxor, tcg_gen_xor_tl); +GEN_SPEOP_LOGIC2(evor, tcg_gen_or_tl); +GEN_SPEOP_LOGIC2(evnor, tcg_gen_nor_tl); +GEN_SPEOP_LOGIC2(eveqv, tcg_gen_eqv_tl); +GEN_SPEOP_LOGIC2(evorc, tcg_gen_orc_tl); +GEN_SPEOP_LOGIC2(evnand, tcg_gen_nand_tl); + +/* SPE logic immediate */ +#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i32 t0; \ + if (unlikely(!ctx->spe_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_SPEU); \ + return; \ + } \ + t0 = tcg_temp_new_i32(); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_opi(t0, t0, rB(ctx->opcode)); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]); \ + tcg_opi(t0, t0, rB(ctx->opcode)); \ + tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ + \ + tcg_temp_free_i32(t0); \ +} +GEN_SPEOP_TCG_LOGIC_IMM2(evslwi, tcg_gen_shli_i32); +GEN_SPEOP_TCG_LOGIC_IMM2(evsrwiu, tcg_gen_shri_i32); +GEN_SPEOP_TCG_LOGIC_IMM2(evsrwis, tcg_gen_sari_i32); +GEN_SPEOP_TCG_LOGIC_IMM2(evrlwi, tcg_gen_rotli_i32); + +/* SPE arithmetic */ +#define GEN_SPEOP_ARITH1(name, tcg_op) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i32 t0; \ + if (unlikely(!ctx->spe_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_SPEU); \ + return; \ + } \ + t0 = tcg_temp_new_i32(); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_op(t0, t0); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]); \ + tcg_op(t0, t0); \ + tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ + \ + tcg_temp_free_i32(t0); \ +} + +static inline void gen_op_evabs(TCGv_i32 ret, TCGv_i32 arg1) +{ + TCGLabel *l1 = gen_new_label(); + TCGLabel *l2 = gen_new_label(); + + tcg_gen_brcondi_i32(TCG_COND_GE, arg1, 0, l1); + tcg_gen_neg_i32(ret, arg1); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_mov_i32(ret, arg1); + gen_set_label(l2); +} +GEN_SPEOP_ARITH1(evabs, gen_op_evabs); +GEN_SPEOP_ARITH1(evneg, tcg_gen_neg_i32); +GEN_SPEOP_ARITH1(evextsb, tcg_gen_ext8s_i32); +GEN_SPEOP_ARITH1(evextsh, tcg_gen_ext16s_i32); +static inline void gen_op_evrndw(TCGv_i32 ret, TCGv_i32 arg1) +{ + tcg_gen_addi_i32(ret, arg1, 0x8000); + tcg_gen_ext16u_i32(ret, ret); +} +GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw); +GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32); +GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32); + +#define GEN_SPEOP_ARITH2(name, tcg_op) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i32 t0, t1; \ + if (unlikely(!ctx->spe_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_SPEU); \ + return; \ + } \ + t0 = tcg_temp_new_i32(); \ + t1 = tcg_temp_new_i32(); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ + tcg_op(t0, t0, t1); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]); \ + tcg_gen_trunc_tl_i32(t1, cpu_gprh[rB(ctx->opcode)]); \ + tcg_op(t0, t0, t1); \ + tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ + \ + tcg_temp_free_i32(t0); \ + tcg_temp_free_i32(t1); \ +} + +static inline void gen_op_evsrwu(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGLabel *l1 = gen_new_label(); + TCGLabel *l2 = gen_new_label(); + TCGv_i32 t0 = tcg_temp_local_new_i32(); + + /* No error here: 6 bits are used */ + tcg_gen_andi_i32(t0, arg2, 0x3F); + tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1); + tcg_gen_shr_i32(ret, arg1, t0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(ret, 0); + gen_set_label(l2); + tcg_temp_free_i32(t0); +} +GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu); +static inline void gen_op_evsrws(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGLabel *l1 = gen_new_label(); + TCGLabel *l2 = gen_new_label(); + TCGv_i32 t0 = tcg_temp_local_new_i32(); + + /* No error here: 6 bits are used */ + tcg_gen_andi_i32(t0, arg2, 0x3F); + tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1); + tcg_gen_sar_i32(ret, arg1, t0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(ret, 0); + gen_set_label(l2); + tcg_temp_free_i32(t0); +} +GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws); +static inline void gen_op_evslw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGLabel *l1 = gen_new_label(); + TCGLabel *l2 = gen_new_label(); + TCGv_i32 t0 = tcg_temp_local_new_i32(); + + /* No error here: 6 bits are used */ + tcg_gen_andi_i32(t0, arg2, 0x3F); + tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1); + tcg_gen_shl_i32(ret, arg1, t0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_i32(ret, 0); + gen_set_label(l2); + tcg_temp_free_i32(t0); +} +GEN_SPEOP_ARITH2(evslw, gen_op_evslw); +static inline void gen_op_evrlw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t0, arg2, 0x1F); + tcg_gen_rotl_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); +} +GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw); +static inline void gen_evmergehi(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); +} +GEN_SPEOP_ARITH2(evaddw, tcg_gen_add_i32); +static inline void gen_op_evsubf(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_sub_i32(ret, arg2, arg1); +} +GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf); + +/* SPE arithmetic immediate */ +#define GEN_SPEOP_ARITH_IMM2(name, tcg_op) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i32 t0; \ + if (unlikely(!ctx->spe_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_SPEU); \ + return; \ + } \ + t0 = tcg_temp_new_i32(); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ + tcg_op(t0, t0, rA(ctx->opcode)); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gprh[rB(ctx->opcode)]); \ + tcg_op(t0, t0, rA(ctx->opcode)); \ + tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ + \ + tcg_temp_free_i32(t0); \ +} +GEN_SPEOP_ARITH_IMM2(evaddiw, tcg_gen_addi_i32); +GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32); + +/* SPE comparison */ +#define GEN_SPEOP_COMP(name, tcg_cond) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_SPEU); \ + return; \ + } \ + TCGLabel *l1 = gen_new_label(); \ + TCGLabel *l2 = gen_new_label(); \ + TCGLabel *l3 = gen_new_label(); \ + TCGLabel *l4 = gen_new_label(); \ + \ + tcg_gen_ext32s_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); \ + tcg_gen_ext32s_tl(cpu_gpr[rB(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ + tcg_gen_ext32s_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); \ + tcg_gen_ext32s_tl(cpu_gprh[rB(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); \ + \ + tcg_gen_brcond_tl(tcg_cond, cpu_gpr[rA(ctx->opcode)], \ + cpu_gpr[rB(ctx->opcode)], l1); \ + tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0); \ + tcg_gen_br(l2); \ + gen_set_label(l1); \ + tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], \ + CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL); \ + gen_set_label(l2); \ + tcg_gen_brcond_tl(tcg_cond, cpu_gprh[rA(ctx->opcode)], \ + cpu_gprh[rB(ctx->opcode)], l3); \ + tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], \ + ~(CRF_CH | CRF_CH_AND_CL)); \ + tcg_gen_br(l4); \ + gen_set_label(l3); \ + tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], \ + CRF_CH | CRF_CH_OR_CL); \ + gen_set_label(l4); \ +} +GEN_SPEOP_COMP(evcmpgtu, TCG_COND_GTU); +GEN_SPEOP_COMP(evcmpgts, TCG_COND_GT); +GEN_SPEOP_COMP(evcmpltu, TCG_COND_LTU); +GEN_SPEOP_COMP(evcmplts, TCG_COND_LT); +GEN_SPEOP_COMP(evcmpeq, TCG_COND_EQ); + +/* SPE misc */ +static inline void gen_brinc(DisasContext *ctx) +{ + /* Note: brinc is usable even if SPE is disabled */ + gen_helper_brinc(cpu_gpr[rD(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); +} +static inline void gen_evmergelo(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); +} +static inline void gen_evmergehilo(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); +} +static inline void gen_evmergelohi(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + if (rD(ctx->opcode) == rA(ctx->opcode)) { + TCGv tmp = tcg_temp_new(); + tcg_gen_mov_tl(tmp, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], tmp); + tcg_temp_free(tmp); + } else { + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + } +} +static inline void gen_evsplati(DisasContext *ctx) +{ + uint64_t imm = ((int32_t)(rA(ctx->opcode) << 27)) >> 27; + + tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], imm); + tcg_gen_movi_tl(cpu_gprh[rD(ctx->opcode)], imm); +} +static inline void gen_evsplatfi(DisasContext *ctx) +{ + uint64_t imm = rA(ctx->opcode) << 27; + + tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], imm); + tcg_gen_movi_tl(cpu_gprh[rD(ctx->opcode)], imm); +} + +static inline void gen_evsel(DisasContext *ctx) +{ + TCGLabel *l1 = gen_new_label(); + TCGLabel *l2 = gen_new_label(); + TCGLabel *l3 = gen_new_label(); + TCGLabel *l4 = gen_new_label(); + TCGv_i32 t0 = tcg_temp_local_new_i32(); + + tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 3); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); + gen_set_label(l2); + tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 2); + tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l3); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_br(l4); + gen_set_label(l3); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + gen_set_label(l4); + tcg_temp_free_i32(t0); +} + +static void gen_evsel0(DisasContext *ctx) +{ + gen_evsel(ctx); +} + +static void gen_evsel1(DisasContext *ctx) +{ + gen_evsel(ctx); +} + +static void gen_evsel2(DisasContext *ctx) +{ + gen_evsel(ctx); +} + +static void gen_evsel3(DisasContext *ctx) +{ + gen_evsel(ctx); +} + +/* Multiply */ + +static inline void gen_evmwumi(DisasContext *ctx) +{ + TCGv_i64 t0, t1; + + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + /* t0 := rA; t1 := rB */ + tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ext32u_i64(t0, t0); + tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_ext32u_i64(t1, t1); + + tcg_gen_mul_i64(t0, t0, t1); /* t0 := rA * rB */ + + gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */ + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +} + +static inline void gen_evmwumia(DisasContext *ctx) +{ + TCGv_i64 tmp; + + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + + gen_evmwumi(ctx); /* rD := rA * rB */ + + tmp = tcg_temp_new_i64(); + + /* acc := rD */ + gen_load_gpr64(tmp, rD(ctx->opcode)); + tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_temp_free_i64(tmp); +} + +static inline void gen_evmwumiaa(DisasContext *ctx) +{ + TCGv_i64 acc; + TCGv_i64 tmp; + + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + + gen_evmwumi(ctx); /* rD := rA * rB */ + + acc = tcg_temp_new_i64(); + tmp = tcg_temp_new_i64(); + + /* tmp := rD */ + gen_load_gpr64(tmp, rD(ctx->opcode)); + + /* Load acc */ + tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + + /* acc := tmp + acc */ + tcg_gen_add_i64(acc, acc, tmp); + + /* Store acc */ + tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + + /* rD := acc */ + gen_store_gpr64(rD(ctx->opcode), acc); + + tcg_temp_free_i64(acc); + tcg_temp_free_i64(tmp); +} + +static inline void gen_evmwsmi(DisasContext *ctx) +{ + TCGv_i64 t0, t1; + + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + /* t0 := rA; t1 := rB */ + tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ext32s_i64(t0, t0); + tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_ext32s_i64(t1, t1); + + tcg_gen_mul_i64(t0, t0, t1); /* t0 := rA * rB */ + + gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */ + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +} + +static inline void gen_evmwsmia(DisasContext *ctx) +{ + TCGv_i64 tmp; + + gen_evmwsmi(ctx); /* rD := rA * rB */ + + tmp = tcg_temp_new_i64(); + + /* acc := rD */ + gen_load_gpr64(tmp, rD(ctx->opcode)); + tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); + + tcg_temp_free_i64(tmp); +} + +static inline void gen_evmwsmiaa(DisasContext *ctx) +{ + TCGv_i64 acc = tcg_temp_new_i64(); + TCGv_i64 tmp = tcg_temp_new_i64(); + + gen_evmwsmi(ctx); /* rD := rA * rB */ + + acc = tcg_temp_new_i64(); + tmp = tcg_temp_new_i64(); + + /* tmp := rD */ + gen_load_gpr64(tmp, rD(ctx->opcode)); + + /* Load acc */ + tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + + /* acc := tmp + acc */ + tcg_gen_add_i64(acc, acc, tmp); + + /* Store acc */ + tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + + /* rD := acc */ + gen_store_gpr64(rD(ctx->opcode), acc); + + tcg_temp_free_i64(acc); + tcg_temp_free_i64(tmp); +} + +GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE); // +GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(speundef, evand, 0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); //// +GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evorc, 0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); //// +GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE); // +GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE); +GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE); //// +GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE); //// +GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE); //// + +/* SPE load and stores */ +static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh) +{ + target_ulong uimm = rB(ctx->opcode); + + if (rA(ctx->opcode) == 0) { + tcg_gen_movi_tl(EA, uimm << sh); + } else { + tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh); + if (NARROW_MODE(ctx)) { + tcg_gen_ext32u_tl(EA, EA); + } + } +} + +static inline void gen_op_evldd(DisasContext *ctx, TCGv addr) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + gen_qemu_ld64(ctx, t0, addr); + gen_store_gpr64(rD(ctx->opcode), t0); + tcg_temp_free_i64(t0); +} + +static inline void gen_op_evldw(DisasContext *ctx, TCGv addr) +{ + gen_qemu_ld32u(ctx, cpu_gprh[rD(ctx->opcode)], addr); + gen_addr_add(ctx, addr, addr, 4); + gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], addr); +} + +static inline void gen_op_evldh(DisasContext *ctx, TCGv addr) +{ + TCGv t0 = tcg_temp_new(); + gen_qemu_ld16u(ctx, t0, addr); + tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16); + gen_addr_add(ctx, addr, addr, 2); + gen_qemu_ld16u(ctx, t0, addr); + tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0); + gen_addr_add(ctx, addr, addr, 2); + gen_qemu_ld16u(ctx, t0, addr); + tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16); + gen_addr_add(ctx, addr, addr, 2); + gen_qemu_ld16u(ctx, t0, addr); + tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); + tcg_temp_free(t0); +} + +static inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr) +{ + TCGv t0 = tcg_temp_new(); + gen_qemu_ld16u(ctx, t0, addr); + tcg_gen_shli_tl(t0, t0, 16); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); + tcg_temp_free(t0); +} + +static inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr) +{ + TCGv t0 = tcg_temp_new(); + gen_qemu_ld16u(ctx, t0, addr); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); + tcg_temp_free(t0); +} + +static inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr) +{ + TCGv t0 = tcg_temp_new(); + gen_qemu_ld16s(ctx, t0, addr); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); + tcg_temp_free(t0); +} + +static inline void gen_op_evlwhe(DisasContext *ctx, TCGv addr) +{ + TCGv t0 = tcg_temp_new(); + gen_qemu_ld16u(ctx, t0, addr); + tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16); + gen_addr_add(ctx, addr, addr, 2); + gen_qemu_ld16u(ctx, t0, addr); + tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16); + tcg_temp_free(t0); +} + +static inline void gen_op_evlwhou(DisasContext *ctx, TCGv addr) +{ + gen_qemu_ld16u(ctx, cpu_gprh[rD(ctx->opcode)], addr); + gen_addr_add(ctx, addr, addr, 2); + gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr); +} + +static inline void gen_op_evlwhos(DisasContext *ctx, TCGv addr) +{ + gen_qemu_ld16s(ctx, cpu_gprh[rD(ctx->opcode)], addr); + gen_addr_add(ctx, addr, addr, 2); + gen_qemu_ld16s(ctx, cpu_gpr[rD(ctx->opcode)], addr); +} + +static inline void gen_op_evlwwsplat(DisasContext *ctx, TCGv addr) +{ + TCGv t0 = tcg_temp_new(); + gen_qemu_ld32u(ctx, t0, addr); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); + tcg_temp_free(t0); +} + +static inline void gen_op_evlwhsplat(DisasContext *ctx, TCGv addr) +{ + TCGv t0 = tcg_temp_new(); + gen_qemu_ld16u(ctx, t0, addr); + tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16); + tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0); + gen_addr_add(ctx, addr, addr, 2); + gen_qemu_ld16u(ctx, t0, addr); + tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16); + tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0); + tcg_temp_free(t0); +} + +static inline void gen_op_evstdd(DisasContext *ctx, TCGv addr) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + gen_load_gpr64(t0, rS(ctx->opcode)); + gen_qemu_st64(ctx, t0, addr); + tcg_temp_free_i64(t0); +} + +static inline void gen_op_evstdw(DisasContext *ctx, TCGv addr) +{ + gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr); + gen_addr_add(ctx, addr, addr, 4); + gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr); +} + +static inline void gen_op_evstdh(DisasContext *ctx, TCGv addr) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16); + gen_qemu_st16(ctx, t0, addr); + gen_addr_add(ctx, addr, addr, 2); + gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr); + gen_addr_add(ctx, addr, addr, 2); + tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16); + gen_qemu_st16(ctx, t0, addr); + tcg_temp_free(t0); + gen_addr_add(ctx, addr, addr, 2); + gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr); +} + +static inline void gen_op_evstwhe(DisasContext *ctx, TCGv addr) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16); + gen_qemu_st16(ctx, t0, addr); + gen_addr_add(ctx, addr, addr, 2); + tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16); + gen_qemu_st16(ctx, t0, addr); + tcg_temp_free(t0); +} + +static inline void gen_op_evstwho(DisasContext *ctx, TCGv addr) +{ + gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr); + gen_addr_add(ctx, addr, addr, 2); + gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr); +} + +static inline void gen_op_evstwwe(DisasContext *ctx, TCGv addr) +{ + gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr); +} + +static inline void gen_op_evstwwo(DisasContext *ctx, TCGv addr) +{ + gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr); +} + +#define GEN_SPEOP_LDST(name, opc2, sh) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + TCGv t0; \ + if (unlikely(!ctx->spe_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_SPEU); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_INT); \ + t0 = tcg_temp_new(); \ + if (Rc(ctx->opcode)) { \ + gen_addr_spe_imm_index(ctx, t0, sh); \ + } else { \ + gen_addr_reg_index(ctx, t0); \ + } \ + gen_op_##name(ctx, t0); \ + tcg_temp_free(t0); \ +} + +GEN_SPEOP_LDST(evldd, 0x00, 3); +GEN_SPEOP_LDST(evldw, 0x01, 3); +GEN_SPEOP_LDST(evldh, 0x02, 3); +GEN_SPEOP_LDST(evlhhesplat, 0x04, 1); +GEN_SPEOP_LDST(evlhhousplat, 0x06, 1); +GEN_SPEOP_LDST(evlhhossplat, 0x07, 1); +GEN_SPEOP_LDST(evlwhe, 0x08, 2); +GEN_SPEOP_LDST(evlwhou, 0x0A, 2); +GEN_SPEOP_LDST(evlwhos, 0x0B, 2); +GEN_SPEOP_LDST(evlwwsplat, 0x0C, 2); +GEN_SPEOP_LDST(evlwhsplat, 0x0E, 2); + +GEN_SPEOP_LDST(evstdd, 0x10, 3); +GEN_SPEOP_LDST(evstdw, 0x11, 3); +GEN_SPEOP_LDST(evstdh, 0x12, 3); +GEN_SPEOP_LDST(evstwhe, 0x18, 2); +GEN_SPEOP_LDST(evstwho, 0x1A, 2); +GEN_SPEOP_LDST(evstwwe, 0x1C, 2); +GEN_SPEOP_LDST(evstwwo, 0x1E, 2); + +/* Multiply and add - TODO */ +#if 0 +GEN_SPE(speundef, evmhessf, 0x01, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);// +GEN_SPE(speundef, evmhossf, 0x03, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumi, evmhesmi, 0x04, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmf, 0x05, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumi, evmhosmi, 0x06, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmf, 0x07, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfa, 0x11, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfa, 0x13, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumia, evmhesmia, 0x14, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfa, 0x15, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumia, evmhosmia, 0x16, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfa, 0x17, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(speundef, evmwhssf, 0x03, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumi, speundef, 0x04, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evmwhumi, evmwhsmi, 0x06, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhsmf, 0x07, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssf, 0x09, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmf, 0x0D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhssfa, 0x13, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumia, speundef, 0x14, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evmwhumia, evmwhsmia, 0x16, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhsmfa, 0x17, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfa, 0x19, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfa, 0x1D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evadduiaaw, evaddsiaaw, 0x00, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evsubfusiaaw, evsubfssiaaw, 0x01, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evaddumiaaw, evaddsmiaaw, 0x04, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evsubfumiaaw, evsubfsmiaaw, 0x05, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evdivws, evdivwu, 0x06, 0x13, 0x00000000, 0x00000000, PPC_SPE); + +GEN_SPE(evmheusiaaw, evmhessiaaw, 0x00, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfaaw, 0x01, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhousiaaw, evmhossiaaw, 0x02, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfaaw, 0x03, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumiaaw, evmhesmiaaw, 0x04, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfaaw, 0x05, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumiaaw, evmhosmiaaw, 0x06, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfaaw, 0x07, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhegumiaa, evmhegsmiaa, 0x14, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhegsmfaa, 0x15, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhogumiaa, evmhogsmiaa, 0x16, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhogsmfaa, 0x17, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evmwlusiaaw, evmwlssiaaw, 0x00, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumiaaw, evmwlsmiaaw, 0x04, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfaa, 0x09, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfaa, 0x0D, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evmheusianw, evmhessianw, 0x00, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfanw, 0x01, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhousianw, evmhossianw, 0x02, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfanw, 0x03, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumianw, evmhesmianw, 0x04, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfanw, 0x05, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumianw, evmhosmianw, 0x06, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfanw, 0x07, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhegumian, evmhegsmian, 0x14, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhegsmfan, 0x15, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhigumian, evmhigsmian, 0x16, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhogsmfan, 0x17, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evmwlusianw, evmwlssianw, 0x00, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumianw, evmwlsmianw, 0x04, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfan, 0x09, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwumian, evmwsmian, 0x0C, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE); +#endif + +/*** SPE floating-point extension ***/ +#define GEN_SPEFPUOP_CONV_32_32(name) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i32 t0 = tcg_temp_new_i32(); \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(t0, cpu_env, t0); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ + tcg_temp_free_i32(t0); \ +} +#define GEN_SPEFPUOP_CONV_32_64(name) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i64 t0 = tcg_temp_new_i64(); \ + TCGv_i32 t1 = tcg_temp_new_i32(); \ + gen_load_gpr64(t0, rB(ctx->opcode)); \ + gen_helper_##name(t1, cpu_env, t0); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1); \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i32(t1); \ +} +#define GEN_SPEFPUOP_CONV_64_32(name) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i64 t0 = tcg_temp_new_i64(); \ + TCGv_i32 t1 = tcg_temp_new_i32(); \ + tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(t0, cpu_env, t1); \ + gen_store_gpr64(rD(ctx->opcode), t0); \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i32(t1); \ +} +#define GEN_SPEFPUOP_CONV_64_64(name) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i64 t0 = tcg_temp_new_i64(); \ + gen_load_gpr64(t0, rB(ctx->opcode)); \ + gen_helper_##name(t0, cpu_env, t0); \ + gen_store_gpr64(rD(ctx->opcode), t0); \ + tcg_temp_free_i64(t0); \ +} +#define GEN_SPEFPUOP_ARITH2_32_32(name) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i32 t0, t1; \ + if (unlikely(!ctx->spe_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_SPEU); \ + return; \ + } \ + t0 = tcg_temp_new_i32(); \ + t1 = tcg_temp_new_i32(); \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(t0, cpu_env, t0, t1); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ + \ + tcg_temp_free_i32(t0); \ + tcg_temp_free_i32(t1); \ +} +#define GEN_SPEFPUOP_ARITH2_64_64(name) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i64 t0, t1; \ + if (unlikely(!ctx->spe_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_SPEU); \ + return; \ + } \ + t0 = tcg_temp_new_i64(); \ + t1 = tcg_temp_new_i64(); \ + gen_load_gpr64(t0, rA(ctx->opcode)); \ + gen_load_gpr64(t1, rB(ctx->opcode)); \ + gen_helper_##name(t0, cpu_env, t0, t1); \ + gen_store_gpr64(rD(ctx->opcode), t0); \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i64(t1); \ +} +#define GEN_SPEFPUOP_COMP_32(name) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i32 t0, t1; \ + if (unlikely(!ctx->spe_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_SPEU); \ + return; \ + } \ + t0 = tcg_temp_new_i32(); \ + t1 = tcg_temp_new_i32(); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ + \ + tcg_temp_free_i32(t0); \ + tcg_temp_free_i32(t1); \ +} +#define GEN_SPEFPUOP_COMP_64(name) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i64 t0, t1; \ + if (unlikely(!ctx->spe_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_SPEU); \ + return; \ + } \ + t0 = tcg_temp_new_i64(); \ + t1 = tcg_temp_new_i64(); \ + gen_load_gpr64(t0, rA(ctx->opcode)); \ + gen_load_gpr64(t1, rB(ctx->opcode)); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i64(t1); \ +} + +/* Single precision floating-point vectors operations */ +/* Arithmetic */ +GEN_SPEFPUOP_ARITH2_64_64(evfsadd); +GEN_SPEFPUOP_ARITH2_64_64(evfssub); +GEN_SPEFPUOP_ARITH2_64_64(evfsmul); +GEN_SPEFPUOP_ARITH2_64_64(evfsdiv); +static inline void gen_evfsabs(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + ~0x80000000); + tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + ~0x80000000); +} +static inline void gen_evfsnabs(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + 0x80000000); + tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + 0x80000000); +} +static inline void gen_evfsneg(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + 0x80000000); + tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + 0x80000000); +} + +/* Conversion */ +GEN_SPEFPUOP_CONV_64_64(evfscfui); +GEN_SPEFPUOP_CONV_64_64(evfscfsi); +GEN_SPEFPUOP_CONV_64_64(evfscfuf); +GEN_SPEFPUOP_CONV_64_64(evfscfsf); +GEN_SPEFPUOP_CONV_64_64(evfsctui); +GEN_SPEFPUOP_CONV_64_64(evfsctsi); +GEN_SPEFPUOP_CONV_64_64(evfsctuf); +GEN_SPEFPUOP_CONV_64_64(evfsctsf); +GEN_SPEFPUOP_CONV_64_64(evfsctuiz); +GEN_SPEFPUOP_CONV_64_64(evfsctsiz); + +/* Comparison */ +GEN_SPEFPUOP_COMP_64(evfscmpgt); +GEN_SPEFPUOP_COMP_64(evfscmplt); +GEN_SPEFPUOP_COMP_64(evfscmpeq); +GEN_SPEFPUOP_COMP_64(evfststgt); +GEN_SPEFPUOP_COMP_64(evfststlt); +GEN_SPEFPUOP_COMP_64(evfststeq); + +/* Opcodes definitions */ +GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); // +GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // + +/* Single precision floating-point operations */ +/* Arithmetic */ +GEN_SPEFPUOP_ARITH2_32_32(efsadd); +GEN_SPEFPUOP_ARITH2_32_32(efssub); +GEN_SPEFPUOP_ARITH2_32_32(efsmul); +GEN_SPEFPUOP_ARITH2_32_32(efsdiv); +static inline void gen_efsabs(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL); +} +static inline void gen_efsnabs(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); +} +static inline void gen_efsneg(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); +} + +/* Conversion */ +GEN_SPEFPUOP_CONV_32_32(efscfui); +GEN_SPEFPUOP_CONV_32_32(efscfsi); +GEN_SPEFPUOP_CONV_32_32(efscfuf); +GEN_SPEFPUOP_CONV_32_32(efscfsf); +GEN_SPEFPUOP_CONV_32_32(efsctui); +GEN_SPEFPUOP_CONV_32_32(efsctsi); +GEN_SPEFPUOP_CONV_32_32(efsctuf); +GEN_SPEFPUOP_CONV_32_32(efsctsf); +GEN_SPEFPUOP_CONV_32_32(efsctuiz); +GEN_SPEFPUOP_CONV_32_32(efsctsiz); +GEN_SPEFPUOP_CONV_32_64(efscfd); + +/* Comparison */ +GEN_SPEFPUOP_COMP_32(efscmpgt); +GEN_SPEFPUOP_COMP_32(efscmplt); +GEN_SPEFPUOP_COMP_32(efscmpeq); +GEN_SPEFPUOP_COMP_32(efststgt); +GEN_SPEFPUOP_COMP_32(efststlt); +GEN_SPEFPUOP_COMP_32(efststeq); + +/* Opcodes definitions */ +GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); // +GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // + +/* Double precision floating-point operations */ +/* Arithmetic */ +GEN_SPEFPUOP_ARITH2_64_64(efdadd); +GEN_SPEFPUOP_ARITH2_64_64(efdsub); +GEN_SPEFPUOP_ARITH2_64_64(efdmul); +GEN_SPEFPUOP_ARITH2_64_64(efddiv); +static inline void gen_efdabs(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + ~0x80000000); +} +static inline void gen_efdnabs(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + 0x80000000); +} +static inline void gen_efdneg(DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + gen_exception(ctx, POWERPC_EXCP_SPEU); + return; + } + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + 0x80000000); +} + +/* Conversion */ +GEN_SPEFPUOP_CONV_64_32(efdcfui); +GEN_SPEFPUOP_CONV_64_32(efdcfsi); +GEN_SPEFPUOP_CONV_64_32(efdcfuf); +GEN_SPEFPUOP_CONV_64_32(efdcfsf); +GEN_SPEFPUOP_CONV_32_64(efdctui); +GEN_SPEFPUOP_CONV_32_64(efdctsi); +GEN_SPEFPUOP_CONV_32_64(efdctuf); +GEN_SPEFPUOP_CONV_32_64(efdctsf); +GEN_SPEFPUOP_CONV_32_64(efdctuiz); +GEN_SPEFPUOP_CONV_32_64(efdctsiz); +GEN_SPEFPUOP_CONV_64_32(efdcfs); +GEN_SPEFPUOP_CONV_64_64(efdcfuid); +GEN_SPEFPUOP_CONV_64_64(efdcfsid); +GEN_SPEFPUOP_CONV_64_64(efdctuidz); +GEN_SPEFPUOP_CONV_64_64(efdctsidz); + +/* Comparison */ +GEN_SPEFPUOP_COMP_64(efdcmpgt); +GEN_SPEFPUOP_COMP_64(efdcmplt); +GEN_SPEFPUOP_COMP_64(efdcmpeq); +GEN_SPEFPUOP_COMP_64(efdtstgt); +GEN_SPEFPUOP_COMP_64(efdtstlt); +GEN_SPEFPUOP_COMP_64(efdtsteq); + +/* Opcodes definitions */ +GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE); // +GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // +GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // + +#undef GEN_SPE +#undef GEN_SPEOP_LDST diff --git a/target-ppc/translate/spe-ops.c b/target-ppc/translate/spe-ops.c new file mode 100644 index 0000000000..7efe8b8746 --- /dev/null +++ b/target-ppc/translate/spe-ops.c @@ -0,0 +1,105 @@ +GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE), +GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE), +GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE), +GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE), + +#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ + GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE) +GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE), +GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(speundef, evand, 0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE), +GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(speundef, evorc, 0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE), +GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE), +GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE), +GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE), +GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE), +GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE), + +GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE), +GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), + +GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE), +GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), + +GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE), +GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE), +GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE), +GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE), + +#define GEN_SPEOP_LDST(name, opc2, sh) \ +GEN_HANDLER(name, 0x04, opc2, 0x0C, 0x00000000, PPC_SPE) +GEN_SPEOP_LDST(evldd, 0x00, 3), +GEN_SPEOP_LDST(evldw, 0x01, 3), +GEN_SPEOP_LDST(evldh, 0x02, 3), +GEN_SPEOP_LDST(evlhhesplat, 0x04, 1), +GEN_SPEOP_LDST(evlhhousplat, 0x06, 1), +GEN_SPEOP_LDST(evlhhossplat, 0x07, 1), +GEN_SPEOP_LDST(evlwhe, 0x08, 2), +GEN_SPEOP_LDST(evlwhou, 0x0A, 2), +GEN_SPEOP_LDST(evlwhos, 0x0B, 2), +GEN_SPEOP_LDST(evlwwsplat, 0x0C, 2), +GEN_SPEOP_LDST(evlwhsplat, 0x0E, 2), + +GEN_SPEOP_LDST(evstdd, 0x10, 3), +GEN_SPEOP_LDST(evstdw, 0x11, 3), +GEN_SPEOP_LDST(evstdh, 0x12, 3), +GEN_SPEOP_LDST(evstwhe, 0x18, 2), +GEN_SPEOP_LDST(evstwho, 0x1A, 2), +GEN_SPEOP_LDST(evstwwe, 0x1C, 2), +GEN_SPEOP_LDST(evstwwo, 0x1E, 2), From 8b25cdd371e99221b27ddcfaa137cfd6c56df7c1 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:22 +1000 Subject: [PATCH 19/64] ppc: Move DFP ops out of translate.c Makes things a bit more manageable Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate.c | 365 +------------------------------- target-ppc/translate/dfp-impl.c | 212 +++++++++++++++++++ target-ppc/translate/dfp-ops.c | 151 +++++++++++++ 3 files changed, 365 insertions(+), 363 deletions(-) create mode 100644 target-ppc/translate/dfp-impl.c create mode 100644 target-ppc/translate/dfp-ops.c diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 5531d4ec24..dac91f2c24 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -7560,210 +7560,7 @@ static void gen_xxsldwi(DisasContext *ctx) tcg_temp_free_i64(xtl); } -/*** Decimal Floating Point ***/ - -static inline TCGv_ptr gen_fprp_ptr(int reg) -{ - TCGv_ptr r = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, fpr[reg])); - return r; -} - -#define GEN_DFP_T_A_B_Rc(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr rd, ra, rb; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->nip - 4); \ - rd = gen_fprp_ptr(rD(ctx->opcode)); \ - ra = gen_fprp_ptr(rA(ctx->opcode)); \ - rb = gen_fprp_ptr(rB(ctx->opcode)); \ - gen_helper_##name(cpu_env, rd, ra, rb); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ - tcg_temp_free_ptr(rd); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ -} - -#define GEN_DFP_BF_A_B(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr ra, rb; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->nip - 4); \ - ra = gen_fprp_ptr(rA(ctx->opcode)); \ - rb = gen_fprp_ptr(rB(ctx->opcode)); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ - cpu_env, ra, rb); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ -} - -#define GEN_DFP_BF_A_DCM(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr ra; \ - TCGv_i32 dcm; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->nip - 4); \ - ra = gen_fprp_ptr(rA(ctx->opcode)); \ - dcm = tcg_const_i32(DCM(ctx->opcode)); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ - cpu_env, ra, dcm); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_i32(dcm); \ -} - -#define GEN_DFP_T_B_U32_U32_Rc(name, u32f1, u32f2) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr rt, rb; \ - TCGv_i32 u32_1, u32_2; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->nip - 4); \ - rt = gen_fprp_ptr(rD(ctx->opcode)); \ - rb = gen_fprp_ptr(rB(ctx->opcode)); \ - u32_1 = tcg_const_i32(u32f1(ctx->opcode)); \ - u32_2 = tcg_const_i32(u32f2(ctx->opcode)); \ - gen_helper_##name(cpu_env, rt, rb, u32_1, u32_2); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ - tcg_temp_free_ptr(rt); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_i32(u32_1); \ - tcg_temp_free_i32(u32_2); \ -} - -#define GEN_DFP_T_A_B_I32_Rc(name, i32fld) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr rt, ra, rb; \ - TCGv_i32 i32; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->nip - 4); \ - rt = gen_fprp_ptr(rD(ctx->opcode)); \ - ra = gen_fprp_ptr(rA(ctx->opcode)); \ - rb = gen_fprp_ptr(rB(ctx->opcode)); \ - i32 = tcg_const_i32(i32fld(ctx->opcode)); \ - gen_helper_##name(cpu_env, rt, ra, rb, i32); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ - tcg_temp_free_ptr(rt); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_i32(i32); \ - } - -#define GEN_DFP_T_B_Rc(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr rt, rb; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->nip - 4); \ - rt = gen_fprp_ptr(rD(ctx->opcode)); \ - rb = gen_fprp_ptr(rB(ctx->opcode)); \ - gen_helper_##name(cpu_env, rt, rb); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ - tcg_temp_free_ptr(rt); \ - tcg_temp_free_ptr(rb); \ - } - -#define GEN_DFP_T_FPR_I32_Rc(name, fprfld, i32fld) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr rt, rs; \ - TCGv_i32 i32; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->nip - 4); \ - rt = gen_fprp_ptr(rD(ctx->opcode)); \ - rs = gen_fprp_ptr(fprfld(ctx->opcode)); \ - i32 = tcg_const_i32(i32fld(ctx->opcode)); \ - gen_helper_##name(cpu_env, rt, rs, i32); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ - tcg_temp_free_ptr(rt); \ - tcg_temp_free_ptr(rs); \ - tcg_temp_free_i32(i32); \ -} - -GEN_DFP_T_A_B_Rc(dadd) -GEN_DFP_T_A_B_Rc(daddq) -GEN_DFP_T_A_B_Rc(dsub) -GEN_DFP_T_A_B_Rc(dsubq) -GEN_DFP_T_A_B_Rc(dmul) -GEN_DFP_T_A_B_Rc(dmulq) -GEN_DFP_T_A_B_Rc(ddiv) -GEN_DFP_T_A_B_Rc(ddivq) -GEN_DFP_BF_A_B(dcmpu) -GEN_DFP_BF_A_B(dcmpuq) -GEN_DFP_BF_A_B(dcmpo) -GEN_DFP_BF_A_B(dcmpoq) -GEN_DFP_BF_A_DCM(dtstdc) -GEN_DFP_BF_A_DCM(dtstdcq) -GEN_DFP_BF_A_DCM(dtstdg) -GEN_DFP_BF_A_DCM(dtstdgq) -GEN_DFP_BF_A_B(dtstex) -GEN_DFP_BF_A_B(dtstexq) -GEN_DFP_BF_A_B(dtstsf) -GEN_DFP_BF_A_B(dtstsfq) -GEN_DFP_T_B_U32_U32_Rc(dquai, SIMM5, RMC) -GEN_DFP_T_B_U32_U32_Rc(dquaiq, SIMM5, RMC) -GEN_DFP_T_A_B_I32_Rc(dqua, RMC) -GEN_DFP_T_A_B_I32_Rc(dquaq, RMC) -GEN_DFP_T_A_B_I32_Rc(drrnd, RMC) -GEN_DFP_T_A_B_I32_Rc(drrndq, RMC) -GEN_DFP_T_B_U32_U32_Rc(drintx, FPW, RMC) -GEN_DFP_T_B_U32_U32_Rc(drintxq, FPW, RMC) -GEN_DFP_T_B_U32_U32_Rc(drintn, FPW, RMC) -GEN_DFP_T_B_U32_U32_Rc(drintnq, FPW, RMC) -GEN_DFP_T_B_Rc(dctdp) -GEN_DFP_T_B_Rc(dctqpq) -GEN_DFP_T_B_Rc(drsp) -GEN_DFP_T_B_Rc(drdpq) -GEN_DFP_T_B_Rc(dcffix) -GEN_DFP_T_B_Rc(dcffixq) -GEN_DFP_T_B_Rc(dctfix) -GEN_DFP_T_B_Rc(dctfixq) -GEN_DFP_T_FPR_I32_Rc(ddedpd, rB, SP) -GEN_DFP_T_FPR_I32_Rc(ddedpdq, rB, SP) -GEN_DFP_T_FPR_I32_Rc(denbcd, rB, SP) -GEN_DFP_T_FPR_I32_Rc(denbcdq, rB, SP) -GEN_DFP_T_B_Rc(dxex) -GEN_DFP_T_B_Rc(dxexq) -GEN_DFP_T_A_B_Rc(diex) -GEN_DFP_T_A_B_Rc(diexq) -GEN_DFP_T_FPR_I32_Rc(dscli, rA, DCM) -GEN_DFP_T_FPR_I32_Rc(dscliq, rA, DCM) -GEN_DFP_T_FPR_I32_Rc(dscri, rA, DCM) -GEN_DFP_T_FPR_I32_Rc(dscriq, rA, DCM) +#include "translate/dfp-impl.c" #include "translate/spe-impl.c" @@ -8906,165 +8703,7 @@ GEN_XXSEL_ROW(0x1F) GEN_XX3FORM_DM(xxpermdi, 0x08, 0x01), -#undef GEN_DFP_T_A_B_Rc -#undef GEN_DFP_BF_A_B -#undef GEN_DFP_BF_A_DCM -#undef GEN_DFP_T_B_U32_U32_Rc -#undef GEN_DFP_T_A_B_I32_Rc -#undef GEN_DFP_T_B_Rc -#undef GEN_DFP_T_FPR_I32_Rc - -#define _GEN_DFP_LONG(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3B, op1, op2, mask, PPC_NONE, PPC2_DFP) - -#define _GEN_DFP_LONGx2(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP) - -#define _GEN_DFP_LONGx4(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3B, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3B, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP) - -#define _GEN_DFP_QUAD(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3F, op1, op2, mask, PPC_NONE, PPC2_DFP) - -#define _GEN_DFP_QUADx2(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP) - -#define _GEN_DFP_QUADx4(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3F, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3F, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP) - -#define GEN_DFP_T_A_B_Rc(name, op1, op2) \ -_GEN_DFP_LONG(name, op1, op2, 0x00000000) - -#define GEN_DFP_Tp_Ap_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x00210800) - -#define GEN_DFP_Tp_A_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x00200800) - -#define GEN_DFP_T_B_Rc(name, op1, op2) \ -_GEN_DFP_LONG(name, op1, op2, 0x001F0000) - -#define GEN_DFP_Tp_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x003F0800) - -#define GEN_DFP_Tp_B_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x003F0000) - -#define GEN_DFP_T_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x001F0800) - -#define GEN_DFP_BF_A_B(name, op1, op2) \ -_GEN_DFP_LONG(name, op1, op2, 0x00000001) - -#define GEN_DFP_BF_Ap_Bp(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x00610801) - -#define GEN_DFP_BF_A_Bp(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x00600801) - -#define GEN_DFP_BF_A_DCM(name, op1, op2) \ -_GEN_DFP_LONGx2(name, op1, op2, 0x00600001) - -#define GEN_DFP_BF_Ap_DCM(name, op1, op2) \ -_GEN_DFP_QUADx2(name, op1, op2, 0x00610001) - -#define GEN_DFP_T_A_B_RMC_Rc(name, op1, op2) \ -_GEN_DFP_LONGx4(name, op1, op2, 0x00000000) - -#define GEN_DFP_Tp_Ap_Bp_RMC_Rc(name, op1, op2) \ -_GEN_DFP_QUADx4(name, op1, op2, 0x02010800) - -#define GEN_DFP_Tp_A_Bp_RMC_Rc(name, op1, op2) \ -_GEN_DFP_QUADx4(name, op1, op2, 0x02000800) - -#define GEN_DFP_TE_T_B_RMC_Rc(name, op1, op2) \ -_GEN_DFP_LONGx4(name, op1, op2, 0x00000000) - -#define GEN_DFP_TE_Tp_Bp_RMC_Rc(name, op1, op2) \ -_GEN_DFP_QUADx4(name, op1, op2, 0x00200800) - -#define GEN_DFP_R_T_B_RMC_Rc(name, op1, op2) \ -_GEN_DFP_LONGx4(name, op1, op2, 0x001E0000) - -#define GEN_DFP_R_Tp_Bp_RMC_Rc(name, op1, op2) \ -_GEN_DFP_QUADx4(name, op1, op2, 0x003E0800) - -#define GEN_DFP_SP_T_B_Rc(name, op1, op2) \ -_GEN_DFP_LONG(name, op1, op2, 0x00070000) - -#define GEN_DFP_SP_Tp_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x00270800) - -#define GEN_DFP_S_T_B_Rc(name, op1, op2) \ -_GEN_DFP_LONG(name, op1, op2, 0x000F0000) - -#define GEN_DFP_S_Tp_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x002F0800) - -#define GEN_DFP_T_A_SH_Rc(name, op1, op2) \ -_GEN_DFP_LONGx2(name, op1, op2, 0x00000000) - -#define GEN_DFP_Tp_Ap_SH_Rc(name, op1, op2) \ -_GEN_DFP_QUADx2(name, op1, op2, 0x00210000) - -GEN_DFP_T_A_B_Rc(dadd, 0x02, 0x00), -GEN_DFP_Tp_Ap_Bp_Rc(daddq, 0x02, 0x00), -GEN_DFP_T_A_B_Rc(dsub, 0x02, 0x10), -GEN_DFP_Tp_Ap_Bp_Rc(dsubq, 0x02, 0x10), -GEN_DFP_T_A_B_Rc(dmul, 0x02, 0x01), -GEN_DFP_Tp_Ap_Bp_Rc(dmulq, 0x02, 0x01), -GEN_DFP_T_A_B_Rc(ddiv, 0x02, 0x11), -GEN_DFP_Tp_Ap_Bp_Rc(ddivq, 0x02, 0x11), -GEN_DFP_BF_A_B(dcmpu, 0x02, 0x14), -GEN_DFP_BF_Ap_Bp(dcmpuq, 0x02, 0x14), -GEN_DFP_BF_A_B(dcmpo, 0x02, 0x04), -GEN_DFP_BF_Ap_Bp(dcmpoq, 0x02, 0x04), -GEN_DFP_BF_A_DCM(dtstdc, 0x02, 0x06), -GEN_DFP_BF_Ap_DCM(dtstdcq, 0x02, 0x06), -GEN_DFP_BF_A_DCM(dtstdg, 0x02, 0x07), -GEN_DFP_BF_Ap_DCM(dtstdgq, 0x02, 0x07), -GEN_DFP_BF_A_B(dtstex, 0x02, 0x05), -GEN_DFP_BF_Ap_Bp(dtstexq, 0x02, 0x05), -GEN_DFP_BF_A_B(dtstsf, 0x02, 0x15), -GEN_DFP_BF_A_Bp(dtstsfq, 0x02, 0x15), -GEN_DFP_TE_T_B_RMC_Rc(dquai, 0x03, 0x02), -GEN_DFP_TE_Tp_Bp_RMC_Rc(dquaiq, 0x03, 0x02), -GEN_DFP_T_A_B_RMC_Rc(dqua, 0x03, 0x00), -GEN_DFP_Tp_Ap_Bp_RMC_Rc(dquaq, 0x03, 0x00), -GEN_DFP_T_A_B_RMC_Rc(drrnd, 0x03, 0x01), -GEN_DFP_Tp_A_Bp_RMC_Rc(drrndq, 0x03, 0x01), -GEN_DFP_R_T_B_RMC_Rc(drintx, 0x03, 0x03), -GEN_DFP_R_Tp_Bp_RMC_Rc(drintxq, 0x03, 0x03), -GEN_DFP_R_T_B_RMC_Rc(drintn, 0x03, 0x07), -GEN_DFP_R_Tp_Bp_RMC_Rc(drintnq, 0x03, 0x07), -GEN_DFP_T_B_Rc(dctdp, 0x02, 0x08), -GEN_DFP_Tp_B_Rc(dctqpq, 0x02, 0x08), -GEN_DFP_T_B_Rc(drsp, 0x02, 0x18), -GEN_DFP_Tp_Bp_Rc(drdpq, 0x02, 0x18), -GEN_DFP_T_B_Rc(dcffix, 0x02, 0x19), -GEN_DFP_Tp_B_Rc(dcffixq, 0x02, 0x19), -GEN_DFP_T_B_Rc(dctfix, 0x02, 0x09), -GEN_DFP_T_Bp_Rc(dctfixq, 0x02, 0x09), -GEN_DFP_SP_T_B_Rc(ddedpd, 0x02, 0x0a), -GEN_DFP_SP_Tp_Bp_Rc(ddedpdq, 0x02, 0x0a), -GEN_DFP_S_T_B_Rc(denbcd, 0x02, 0x1a), -GEN_DFP_S_Tp_Bp_Rc(denbcdq, 0x02, 0x1a), -GEN_DFP_T_B_Rc(dxex, 0x02, 0x0b), -GEN_DFP_T_Bp_Rc(dxexq, 0x02, 0x0b), -GEN_DFP_T_A_B_Rc(diex, 0x02, 0x1b), -GEN_DFP_Tp_A_Bp_Rc(diexq, 0x02, 0x1b), -GEN_DFP_T_A_SH_Rc(dscli, 0x02, 0x02), -GEN_DFP_Tp_Ap_SH_Rc(dscliq, 0x02, 0x02), -GEN_DFP_T_A_SH_Rc(dscri, 0x02, 0x03), -GEN_DFP_Tp_Ap_SH_Rc(dscriq, 0x02, 0x03), +#include "translate/dfp-ops.c" #include "translate/spe-ops.c" diff --git a/target-ppc/translate/dfp-impl.c b/target-ppc/translate/dfp-impl.c new file mode 100644 index 0000000000..bf59951b1f --- /dev/null +++ b/target-ppc/translate/dfp-impl.c @@ -0,0 +1,212 @@ +/*** Decimal Floating Point ***/ + +static inline TCGv_ptr gen_fprp_ptr(int reg) +{ + TCGv_ptr r = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, fpr[reg])); + return r; +} + +#define GEN_DFP_T_A_B_Rc(name) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr rd, ra, rb; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + rd = gen_fprp_ptr(rD(ctx->opcode)); \ + ra = gen_fprp_ptr(rA(ctx->opcode)); \ + rb = gen_fprp_ptr(rB(ctx->opcode)); \ + gen_helper_##name(cpu_env, rd, ra, rb); \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ + tcg_temp_free_ptr(rd); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ +} + +#define GEN_DFP_BF_A_B(name) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr ra, rb; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + ra = gen_fprp_ptr(rA(ctx->opcode)); \ + rb = gen_fprp_ptr(rB(ctx->opcode)); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ + cpu_env, ra, rb); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ +} + +#define GEN_DFP_BF_A_DCM(name) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr ra; \ + TCGv_i32 dcm; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + ra = gen_fprp_ptr(rA(ctx->opcode)); \ + dcm = tcg_const_i32(DCM(ctx->opcode)); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ + cpu_env, ra, dcm); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_i32(dcm); \ +} + +#define GEN_DFP_T_B_U32_U32_Rc(name, u32f1, u32f2) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr rt, rb; \ + TCGv_i32 u32_1, u32_2; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + rt = gen_fprp_ptr(rD(ctx->opcode)); \ + rb = gen_fprp_ptr(rB(ctx->opcode)); \ + u32_1 = tcg_const_i32(u32f1(ctx->opcode)); \ + u32_2 = tcg_const_i32(u32f2(ctx->opcode)); \ + gen_helper_##name(cpu_env, rt, rb, u32_1, u32_2); \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ + tcg_temp_free_ptr(rt); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_i32(u32_1); \ + tcg_temp_free_i32(u32_2); \ +} + +#define GEN_DFP_T_A_B_I32_Rc(name, i32fld) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr rt, ra, rb; \ + TCGv_i32 i32; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + rt = gen_fprp_ptr(rD(ctx->opcode)); \ + ra = gen_fprp_ptr(rA(ctx->opcode)); \ + rb = gen_fprp_ptr(rB(ctx->opcode)); \ + i32 = tcg_const_i32(i32fld(ctx->opcode)); \ + gen_helper_##name(cpu_env, rt, ra, rb, i32); \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ + tcg_temp_free_ptr(rt); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_i32(i32); \ + } + +#define GEN_DFP_T_B_Rc(name) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr rt, rb; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + rt = gen_fprp_ptr(rD(ctx->opcode)); \ + rb = gen_fprp_ptr(rB(ctx->opcode)); \ + gen_helper_##name(cpu_env, rt, rb); \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ + tcg_temp_free_ptr(rt); \ + tcg_temp_free_ptr(rb); \ + } + +#define GEN_DFP_T_FPR_I32_Rc(name, fprfld, i32fld) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr rt, rs; \ + TCGv_i32 i32; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + rt = gen_fprp_ptr(rD(ctx->opcode)); \ + rs = gen_fprp_ptr(fprfld(ctx->opcode)); \ + i32 = tcg_const_i32(i32fld(ctx->opcode)); \ + gen_helper_##name(cpu_env, rt, rs, i32); \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ + tcg_temp_free_ptr(rt); \ + tcg_temp_free_ptr(rs); \ + tcg_temp_free_i32(i32); \ +} + +GEN_DFP_T_A_B_Rc(dadd) +GEN_DFP_T_A_B_Rc(daddq) +GEN_DFP_T_A_B_Rc(dsub) +GEN_DFP_T_A_B_Rc(dsubq) +GEN_DFP_T_A_B_Rc(dmul) +GEN_DFP_T_A_B_Rc(dmulq) +GEN_DFP_T_A_B_Rc(ddiv) +GEN_DFP_T_A_B_Rc(ddivq) +GEN_DFP_BF_A_B(dcmpu) +GEN_DFP_BF_A_B(dcmpuq) +GEN_DFP_BF_A_B(dcmpo) +GEN_DFP_BF_A_B(dcmpoq) +GEN_DFP_BF_A_DCM(dtstdc) +GEN_DFP_BF_A_DCM(dtstdcq) +GEN_DFP_BF_A_DCM(dtstdg) +GEN_DFP_BF_A_DCM(dtstdgq) +GEN_DFP_BF_A_B(dtstex) +GEN_DFP_BF_A_B(dtstexq) +GEN_DFP_BF_A_B(dtstsf) +GEN_DFP_BF_A_B(dtstsfq) +GEN_DFP_T_B_U32_U32_Rc(dquai, SIMM5, RMC) +GEN_DFP_T_B_U32_U32_Rc(dquaiq, SIMM5, RMC) +GEN_DFP_T_A_B_I32_Rc(dqua, RMC) +GEN_DFP_T_A_B_I32_Rc(dquaq, RMC) +GEN_DFP_T_A_B_I32_Rc(drrnd, RMC) +GEN_DFP_T_A_B_I32_Rc(drrndq, RMC) +GEN_DFP_T_B_U32_U32_Rc(drintx, FPW, RMC) +GEN_DFP_T_B_U32_U32_Rc(drintxq, FPW, RMC) +GEN_DFP_T_B_U32_U32_Rc(drintn, FPW, RMC) +GEN_DFP_T_B_U32_U32_Rc(drintnq, FPW, RMC) +GEN_DFP_T_B_Rc(dctdp) +GEN_DFP_T_B_Rc(dctqpq) +GEN_DFP_T_B_Rc(drsp) +GEN_DFP_T_B_Rc(drdpq) +GEN_DFP_T_B_Rc(dcffix) +GEN_DFP_T_B_Rc(dcffixq) +GEN_DFP_T_B_Rc(dctfix) +GEN_DFP_T_B_Rc(dctfixq) +GEN_DFP_T_FPR_I32_Rc(ddedpd, rB, SP) +GEN_DFP_T_FPR_I32_Rc(ddedpdq, rB, SP) +GEN_DFP_T_FPR_I32_Rc(denbcd, rB, SP) +GEN_DFP_T_FPR_I32_Rc(denbcdq, rB, SP) +GEN_DFP_T_B_Rc(dxex) +GEN_DFP_T_B_Rc(dxexq) +GEN_DFP_T_A_B_Rc(diex) +GEN_DFP_T_A_B_Rc(diexq) +GEN_DFP_T_FPR_I32_Rc(dscli, rA, DCM) +GEN_DFP_T_FPR_I32_Rc(dscliq, rA, DCM) +GEN_DFP_T_FPR_I32_Rc(dscri, rA, DCM) +GEN_DFP_T_FPR_I32_Rc(dscriq, rA, DCM) + +#undef GEN_DFP_T_A_B_Rc +#undef GEN_DFP_BF_A_B +#undef GEN_DFP_BF_A_DCM +#undef GEN_DFP_T_B_U32_U32_Rc +#undef GEN_DFP_T_A_B_I32_Rc +#undef GEN_DFP_T_B_Rc +#undef GEN_DFP_T_FPR_I32_Rc diff --git a/target-ppc/translate/dfp-ops.c b/target-ppc/translate/dfp-ops.c new file mode 100644 index 0000000000..7f27d0f286 --- /dev/null +++ b/target-ppc/translate/dfp-ops.c @@ -0,0 +1,151 @@ +#define _GEN_DFP_LONG(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3B, op1, op2, mask, PPC_NONE, PPC2_DFP) + +#define _GEN_DFP_LONGx2(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP) + +#define _GEN_DFP_LONGx4(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3B, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3B, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP) + +#define _GEN_DFP_QUAD(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3F, op1, op2, mask, PPC_NONE, PPC2_DFP) + +#define _GEN_DFP_QUADx2(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP) + +#define _GEN_DFP_QUADx4(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3F, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3F, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP) + +#define GEN_DFP_T_A_B_Rc(name, op1, op2) \ +_GEN_DFP_LONG(name, op1, op2, 0x00000000) + +#define GEN_DFP_Tp_Ap_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x00210800) + +#define GEN_DFP_Tp_A_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x00200800) + +#define GEN_DFP_T_B_Rc(name, op1, op2) \ +_GEN_DFP_LONG(name, op1, op2, 0x001F0000) + +#define GEN_DFP_Tp_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x003F0800) + +#define GEN_DFP_Tp_B_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x003F0000) + +#define GEN_DFP_T_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x001F0800) + +#define GEN_DFP_BF_A_B(name, op1, op2) \ +_GEN_DFP_LONG(name, op1, op2, 0x00000001) + +#define GEN_DFP_BF_Ap_Bp(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x00610801) + +#define GEN_DFP_BF_A_Bp(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x00600801) + +#define GEN_DFP_BF_A_DCM(name, op1, op2) \ +_GEN_DFP_LONGx2(name, op1, op2, 0x00600001) + +#define GEN_DFP_BF_Ap_DCM(name, op1, op2) \ +_GEN_DFP_QUADx2(name, op1, op2, 0x00610001) + +#define GEN_DFP_T_A_B_RMC_Rc(name, op1, op2) \ +_GEN_DFP_LONGx4(name, op1, op2, 0x00000000) + +#define GEN_DFP_Tp_Ap_Bp_RMC_Rc(name, op1, op2) \ +_GEN_DFP_QUADx4(name, op1, op2, 0x02010800) + +#define GEN_DFP_Tp_A_Bp_RMC_Rc(name, op1, op2) \ +_GEN_DFP_QUADx4(name, op1, op2, 0x02000800) + +#define GEN_DFP_TE_T_B_RMC_Rc(name, op1, op2) \ +_GEN_DFP_LONGx4(name, op1, op2, 0x00000000) + +#define GEN_DFP_TE_Tp_Bp_RMC_Rc(name, op1, op2) \ +_GEN_DFP_QUADx4(name, op1, op2, 0x00200800) + +#define GEN_DFP_R_T_B_RMC_Rc(name, op1, op2) \ +_GEN_DFP_LONGx4(name, op1, op2, 0x001E0000) + +#define GEN_DFP_R_Tp_Bp_RMC_Rc(name, op1, op2) \ +_GEN_DFP_QUADx4(name, op1, op2, 0x003E0800) + +#define GEN_DFP_SP_T_B_Rc(name, op1, op2) \ +_GEN_DFP_LONG(name, op1, op2, 0x00070000) + +#define GEN_DFP_SP_Tp_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x00270800) + +#define GEN_DFP_S_T_B_Rc(name, op1, op2) \ +_GEN_DFP_LONG(name, op1, op2, 0x000F0000) + +#define GEN_DFP_S_Tp_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x002F0800) + +#define GEN_DFP_T_A_SH_Rc(name, op1, op2) \ +_GEN_DFP_LONGx2(name, op1, op2, 0x00000000) + +#define GEN_DFP_Tp_Ap_SH_Rc(name, op1, op2) \ +_GEN_DFP_QUADx2(name, op1, op2, 0x00210000) + +GEN_DFP_T_A_B_Rc(dadd, 0x02, 0x00), +GEN_DFP_Tp_Ap_Bp_Rc(daddq, 0x02, 0x00), +GEN_DFP_T_A_B_Rc(dsub, 0x02, 0x10), +GEN_DFP_Tp_Ap_Bp_Rc(dsubq, 0x02, 0x10), +GEN_DFP_T_A_B_Rc(dmul, 0x02, 0x01), +GEN_DFP_Tp_Ap_Bp_Rc(dmulq, 0x02, 0x01), +GEN_DFP_T_A_B_Rc(ddiv, 0x02, 0x11), +GEN_DFP_Tp_Ap_Bp_Rc(ddivq, 0x02, 0x11), +GEN_DFP_BF_A_B(dcmpu, 0x02, 0x14), +GEN_DFP_BF_Ap_Bp(dcmpuq, 0x02, 0x14), +GEN_DFP_BF_A_B(dcmpo, 0x02, 0x04), +GEN_DFP_BF_Ap_Bp(dcmpoq, 0x02, 0x04), +GEN_DFP_BF_A_DCM(dtstdc, 0x02, 0x06), +GEN_DFP_BF_Ap_DCM(dtstdcq, 0x02, 0x06), +GEN_DFP_BF_A_DCM(dtstdg, 0x02, 0x07), +GEN_DFP_BF_Ap_DCM(dtstdgq, 0x02, 0x07), +GEN_DFP_BF_A_B(dtstex, 0x02, 0x05), +GEN_DFP_BF_Ap_Bp(dtstexq, 0x02, 0x05), +GEN_DFP_BF_A_B(dtstsf, 0x02, 0x15), +GEN_DFP_BF_A_Bp(dtstsfq, 0x02, 0x15), +GEN_DFP_TE_T_B_RMC_Rc(dquai, 0x03, 0x02), +GEN_DFP_TE_Tp_Bp_RMC_Rc(dquaiq, 0x03, 0x02), +GEN_DFP_T_A_B_RMC_Rc(dqua, 0x03, 0x00), +GEN_DFP_Tp_Ap_Bp_RMC_Rc(dquaq, 0x03, 0x00), +GEN_DFP_T_A_B_RMC_Rc(drrnd, 0x03, 0x01), +GEN_DFP_Tp_A_Bp_RMC_Rc(drrndq, 0x03, 0x01), +GEN_DFP_R_T_B_RMC_Rc(drintx, 0x03, 0x03), +GEN_DFP_R_Tp_Bp_RMC_Rc(drintxq, 0x03, 0x03), +GEN_DFP_R_T_B_RMC_Rc(drintn, 0x03, 0x07), +GEN_DFP_R_Tp_Bp_RMC_Rc(drintnq, 0x03, 0x07), +GEN_DFP_T_B_Rc(dctdp, 0x02, 0x08), +GEN_DFP_Tp_B_Rc(dctqpq, 0x02, 0x08), +GEN_DFP_T_B_Rc(drsp, 0x02, 0x18), +GEN_DFP_Tp_Bp_Rc(drdpq, 0x02, 0x18), +GEN_DFP_T_B_Rc(dcffix, 0x02, 0x19), +GEN_DFP_Tp_B_Rc(dcffixq, 0x02, 0x19), +GEN_DFP_T_B_Rc(dctfix, 0x02, 0x09), +GEN_DFP_T_Bp_Rc(dctfixq, 0x02, 0x09), +GEN_DFP_SP_T_B_Rc(ddedpd, 0x02, 0x0a), +GEN_DFP_SP_Tp_Bp_Rc(ddedpdq, 0x02, 0x0a), +GEN_DFP_S_T_B_Rc(denbcd, 0x02, 0x1a), +GEN_DFP_S_Tp_Bp_Rc(denbcdq, 0x02, 0x1a), +GEN_DFP_T_B_Rc(dxex, 0x02, 0x0b), +GEN_DFP_T_Bp_Rc(dxexq, 0x02, 0x0b), +GEN_DFP_T_A_B_Rc(diex, 0x02, 0x1b), +GEN_DFP_Tp_A_Bp_Rc(diexq, 0x02, 0x1b), +GEN_DFP_T_A_SH_Rc(dscli, 0x02, 0x02), +GEN_DFP_Tp_Ap_SH_Rc(dscliq, 0x02, 0x02), +GEN_DFP_T_A_SH_Rc(dscri, 0x02, 0x03), +GEN_DFP_Tp_Ap_SH_Rc(dscriq, 0x02, 0x03), From 0304af897b4f2b0835808e2ede155afb50408432 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:23 +1000 Subject: [PATCH 20/64] ppc: Move VMX ops out of translate.c Makes things a bit more manageable Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate.c | 1068 +------------------------------ target-ppc/translate/vmx-impl.c | 829 ++++++++++++++++++++++++ target-ppc/translate/vmx-ops.c | 245 +++++++ 3 files changed, 1077 insertions(+), 1065 deletions(-) create mode 100644 target-ppc/translate/vmx-impl.c create mode 100644 target-ppc/translate/vmx-ops.c diff --git a/target-ppc/translate.c b/target-ppc/translate.c index dac91f2c24..210152a68c 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -5241,6 +5241,8 @@ static void gen_rfsvc(DisasContext *ctx) #include "translate/fp-impl.c" +#include "translate/vmx-impl.c" + /* svc is not implemented for now */ /* BookE specific instructions */ @@ -6005,702 +6007,6 @@ static void gen_msgsnd(DisasContext *ctx) #endif /* defined(CONFIG_USER_ONLY) */ } -/*** Altivec vector extension ***/ -/* Altivec registers moves */ - -static inline TCGv_ptr gen_avr_ptr(int reg) -{ - TCGv_ptr r = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, avr[reg])); - return r; -} - -#define GEN_VR_LDX(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - tcg_gen_andi_tl(EA, EA, ~0xf); \ - /* We only need to swap high and low halves. gen_qemu_ld64 does necessary \ - 64-bit byteswap already. */ \ - if (ctx->le_mode) { \ - gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ - tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ - } else { \ - gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ - tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ - } \ - tcg_temp_free(EA); \ -} - -#define GEN_VR_STX(name, opc2, opc3) \ -static void gen_st##name(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - tcg_gen_andi_tl(EA, EA, ~0xf); \ - /* We only need to swap high and low halves. gen_qemu_st64 does necessary \ - 64-bit byteswap already. */ \ - if (ctx->le_mode) { \ - gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ - tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ - } else { \ - gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ - tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ - } \ - tcg_temp_free(EA); \ -} - -#define GEN_VR_LVE(name, opc2, opc3, size) \ -static void gen_lve##name(DisasContext *ctx) \ - { \ - TCGv EA; \ - TCGv_ptr rs; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - if (size > 1) { \ - tcg_gen_andi_tl(EA, EA, ~(size - 1)); \ - } \ - rs = gen_avr_ptr(rS(ctx->opcode)); \ - gen_helper_lve##name(cpu_env, rs, EA); \ - tcg_temp_free(EA); \ - tcg_temp_free_ptr(rs); \ - } - -#define GEN_VR_STVE(name, opc2, opc3, size) \ -static void gen_stve##name(DisasContext *ctx) \ - { \ - TCGv EA; \ - TCGv_ptr rs; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - if (size > 1) { \ - tcg_gen_andi_tl(EA, EA, ~(size - 1)); \ - } \ - rs = gen_avr_ptr(rS(ctx->opcode)); \ - gen_helper_stve##name(cpu_env, rs, EA); \ - tcg_temp_free(EA); \ - tcg_temp_free_ptr(rs); \ - } - -GEN_VR_LDX(lvx, 0x07, 0x03); -/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */ -GEN_VR_LDX(lvxl, 0x07, 0x0B); - -GEN_VR_LVE(bx, 0x07, 0x00, 1); -GEN_VR_LVE(hx, 0x07, 0x01, 2); -GEN_VR_LVE(wx, 0x07, 0x02, 4); - -GEN_VR_STX(svx, 0x07, 0x07); -/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */ -GEN_VR_STX(svxl, 0x07, 0x0F); - -GEN_VR_STVE(bx, 0x07, 0x04, 1); -GEN_VR_STVE(hx, 0x07, 0x05, 2); -GEN_VR_STVE(wx, 0x07, 0x06, 4); - -static void gen_lvsl(DisasContext *ctx) -{ - TCGv_ptr rd; - TCGv EA; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - rd = gen_avr_ptr(rD(ctx->opcode)); - gen_helper_lvsl(rd, EA); - tcg_temp_free(EA); - tcg_temp_free_ptr(rd); -} - -static void gen_lvsr(DisasContext *ctx) -{ - TCGv_ptr rd; - TCGv EA; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - rd = gen_avr_ptr(rD(ctx->opcode)); - gen_helper_lvsr(rd, EA); - tcg_temp_free(EA); - tcg_temp_free_ptr(rd); -} - -static void gen_mfvscr(DisasContext *ctx) -{ - TCGv_i32 t; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - tcg_gen_movi_i64(cpu_avrh[rD(ctx->opcode)], 0); - t = tcg_temp_new_i32(); - tcg_gen_ld_i32(t, cpu_env, offsetof(CPUPPCState, vscr)); - tcg_gen_extu_i32_i64(cpu_avrl[rD(ctx->opcode)], t); - tcg_temp_free_i32(t); -} - -static void gen_mtvscr(DisasContext *ctx) -{ - TCGv_ptr p; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - p = gen_avr_ptr(rB(ctx->opcode)); - gen_helper_mtvscr(cpu_env, p); - tcg_temp_free_ptr(p); -} - -/* Logical operations */ -#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - tcg_op(cpu_avrh[rD(ctx->opcode)], cpu_avrh[rA(ctx->opcode)], cpu_avrh[rB(ctx->opcode)]); \ - tcg_op(cpu_avrl[rD(ctx->opcode)], cpu_avrl[rA(ctx->opcode)], cpu_avrl[rB(ctx->opcode)]); \ -} - -GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16); -GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17); -GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18); -GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19); -GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20); -GEN_VX_LOGICAL(veqv, tcg_gen_eqv_i64, 2, 26); -GEN_VX_LOGICAL(vnand, tcg_gen_nand_i64, 2, 22); -GEN_VX_LOGICAL(vorc, tcg_gen_orc_i64, 2, 21); - -#define GEN_VXFORM(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv_ptr ra, rb, rd; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - ra = gen_avr_ptr(rA(ctx->opcode)); \ - rb = gen_avr_ptr(rB(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name (rd, ra, rb); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ -} - -#define GEN_VXFORM_ENV(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv_ptr ra, rb, rd; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - ra = gen_avr_ptr(rA(ctx->opcode)); \ - rb = gen_avr_ptr(rB(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name(cpu_env, rd, ra, rb); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ -} - -#define GEN_VXFORM3(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv_ptr ra, rb, rc, rd; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - ra = gen_avr_ptr(rA(ctx->opcode)); \ - rb = gen_avr_ptr(rB(ctx->opcode)); \ - rc = gen_avr_ptr(rC(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name(rd, ra, rb, rc); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rc); \ - tcg_temp_free_ptr(rd); \ -} - -/* - * Support for Altivec instruction pairs that use bit 31 (Rc) as - * an opcode bit. In general, these pairs come from different - * versions of the ISA, so we must also support a pair of flags for - * each instruction. - */ -#define GEN_VXFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1) \ -static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ -{ \ - if ((Rc(ctx->opcode) == 0) && \ - ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \ - gen_##name0(ctx); \ - } else if ((Rc(ctx->opcode) == 1) && \ - ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \ - gen_##name1(ctx); \ - } else { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - } \ -} - -GEN_VXFORM(vaddubm, 0, 0); -GEN_VXFORM(vadduhm, 0, 1); -GEN_VXFORM(vadduwm, 0, 2); -GEN_VXFORM(vaddudm, 0, 3); -GEN_VXFORM(vsububm, 0, 16); -GEN_VXFORM(vsubuhm, 0, 17); -GEN_VXFORM(vsubuwm, 0, 18); -GEN_VXFORM(vsubudm, 0, 19); -GEN_VXFORM(vmaxub, 1, 0); -GEN_VXFORM(vmaxuh, 1, 1); -GEN_VXFORM(vmaxuw, 1, 2); -GEN_VXFORM(vmaxud, 1, 3); -GEN_VXFORM(vmaxsb, 1, 4); -GEN_VXFORM(vmaxsh, 1, 5); -GEN_VXFORM(vmaxsw, 1, 6); -GEN_VXFORM(vmaxsd, 1, 7); -GEN_VXFORM(vminub, 1, 8); -GEN_VXFORM(vminuh, 1, 9); -GEN_VXFORM(vminuw, 1, 10); -GEN_VXFORM(vminud, 1, 11); -GEN_VXFORM(vminsb, 1, 12); -GEN_VXFORM(vminsh, 1, 13); -GEN_VXFORM(vminsw, 1, 14); -GEN_VXFORM(vminsd, 1, 15); -GEN_VXFORM(vavgub, 1, 16); -GEN_VXFORM(vavguh, 1, 17); -GEN_VXFORM(vavguw, 1, 18); -GEN_VXFORM(vavgsb, 1, 20); -GEN_VXFORM(vavgsh, 1, 21); -GEN_VXFORM(vavgsw, 1, 22); -GEN_VXFORM(vmrghb, 6, 0); -GEN_VXFORM(vmrghh, 6, 1); -GEN_VXFORM(vmrghw, 6, 2); -GEN_VXFORM(vmrglb, 6, 4); -GEN_VXFORM(vmrglh, 6, 5); -GEN_VXFORM(vmrglw, 6, 6); - -static void gen_vmrgew(DisasContext *ctx) -{ - TCGv_i64 tmp; - int VT, VA, VB; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - VT = rD(ctx->opcode); - VA = rA(ctx->opcode); - VB = rB(ctx->opcode); - tmp = tcg_temp_new_i64(); - tcg_gen_shri_i64(tmp, cpu_avrh[VB], 32); - tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VA], tmp, 0, 32); - tcg_gen_shri_i64(tmp, cpu_avrl[VB], 32); - tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VA], tmp, 0, 32); - tcg_temp_free_i64(tmp); -} - -static void gen_vmrgow(DisasContext *ctx) -{ - int VT, VA, VB; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - VT = rD(ctx->opcode); - VA = rA(ctx->opcode); - VB = rB(ctx->opcode); - - tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VB], cpu_avrh[VA], 32, 32); - tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VB], cpu_avrl[VA], 32, 32); -} - -GEN_VXFORM(vmuloub, 4, 0); -GEN_VXFORM(vmulouh, 4, 1); -GEN_VXFORM(vmulouw, 4, 2); -GEN_VXFORM(vmuluwm, 4, 2); -GEN_VXFORM_DUAL(vmulouw, PPC_ALTIVEC, PPC_NONE, - vmuluwm, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM(vmulosb, 4, 4); -GEN_VXFORM(vmulosh, 4, 5); -GEN_VXFORM(vmulosw, 4, 6); -GEN_VXFORM(vmuleub, 4, 8); -GEN_VXFORM(vmuleuh, 4, 9); -GEN_VXFORM(vmuleuw, 4, 10); -GEN_VXFORM(vmulesb, 4, 12); -GEN_VXFORM(vmulesh, 4, 13); -GEN_VXFORM(vmulesw, 4, 14); -GEN_VXFORM(vslb, 2, 4); -GEN_VXFORM(vslh, 2, 5); -GEN_VXFORM(vslw, 2, 6); -GEN_VXFORM(vsld, 2, 23); -GEN_VXFORM(vsrb, 2, 8); -GEN_VXFORM(vsrh, 2, 9); -GEN_VXFORM(vsrw, 2, 10); -GEN_VXFORM(vsrd, 2, 27); -GEN_VXFORM(vsrab, 2, 12); -GEN_VXFORM(vsrah, 2, 13); -GEN_VXFORM(vsraw, 2, 14); -GEN_VXFORM(vsrad, 2, 15); -GEN_VXFORM(vslo, 6, 16); -GEN_VXFORM(vsro, 6, 17); -GEN_VXFORM(vaddcuw, 0, 6); -GEN_VXFORM(vsubcuw, 0, 22); -GEN_VXFORM_ENV(vaddubs, 0, 8); -GEN_VXFORM_ENV(vadduhs, 0, 9); -GEN_VXFORM_ENV(vadduws, 0, 10); -GEN_VXFORM_ENV(vaddsbs, 0, 12); -GEN_VXFORM_ENV(vaddshs, 0, 13); -GEN_VXFORM_ENV(vaddsws, 0, 14); -GEN_VXFORM_ENV(vsububs, 0, 24); -GEN_VXFORM_ENV(vsubuhs, 0, 25); -GEN_VXFORM_ENV(vsubuws, 0, 26); -GEN_VXFORM_ENV(vsubsbs, 0, 28); -GEN_VXFORM_ENV(vsubshs, 0, 29); -GEN_VXFORM_ENV(vsubsws, 0, 30); -GEN_VXFORM(vadduqm, 0, 4); -GEN_VXFORM(vaddcuq, 0, 5); -GEN_VXFORM3(vaddeuqm, 30, 0); -GEN_VXFORM3(vaddecuq, 30, 0); -GEN_VXFORM_DUAL(vaddeuqm, PPC_NONE, PPC2_ALTIVEC_207, \ - vaddecuq, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM(vsubuqm, 0, 20); -GEN_VXFORM(vsubcuq, 0, 21); -GEN_VXFORM3(vsubeuqm, 31, 0); -GEN_VXFORM3(vsubecuq, 31, 0); -GEN_VXFORM_DUAL(vsubeuqm, PPC_NONE, PPC2_ALTIVEC_207, \ - vsubecuq, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM(vrlb, 2, 0); -GEN_VXFORM(vrlh, 2, 1); -GEN_VXFORM(vrlw, 2, 2); -GEN_VXFORM(vrld, 2, 3); -GEN_VXFORM(vsl, 2, 7); -GEN_VXFORM(vsr, 2, 11); -GEN_VXFORM_ENV(vpkuhum, 7, 0); -GEN_VXFORM_ENV(vpkuwum, 7, 1); -GEN_VXFORM_ENV(vpkudum, 7, 17); -GEN_VXFORM_ENV(vpkuhus, 7, 2); -GEN_VXFORM_ENV(vpkuwus, 7, 3); -GEN_VXFORM_ENV(vpkudus, 7, 19); -GEN_VXFORM_ENV(vpkshus, 7, 4); -GEN_VXFORM_ENV(vpkswus, 7, 5); -GEN_VXFORM_ENV(vpksdus, 7, 21); -GEN_VXFORM_ENV(vpkshss, 7, 6); -GEN_VXFORM_ENV(vpkswss, 7, 7); -GEN_VXFORM_ENV(vpksdss, 7, 23); -GEN_VXFORM(vpkpx, 7, 12); -GEN_VXFORM_ENV(vsum4ubs, 4, 24); -GEN_VXFORM_ENV(vsum4sbs, 4, 28); -GEN_VXFORM_ENV(vsum4shs, 4, 25); -GEN_VXFORM_ENV(vsum2sws, 4, 26); -GEN_VXFORM_ENV(vsumsws, 4, 30); -GEN_VXFORM_ENV(vaddfp, 5, 0); -GEN_VXFORM_ENV(vsubfp, 5, 1); -GEN_VXFORM_ENV(vmaxfp, 5, 16); -GEN_VXFORM_ENV(vminfp, 5, 17); - -#define GEN_VXRFORM1(opname, name, str, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ - { \ - TCGv_ptr ra, rb, rd; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - ra = gen_avr_ptr(rA(ctx->opcode)); \ - rb = gen_avr_ptr(rB(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##opname(cpu_env, rd, ra, rb); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ - } - -#define GEN_VXRFORM(name, opc2, opc3) \ - GEN_VXRFORM1(name, name, #name, opc2, opc3) \ - GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4))) - -/* - * Support for Altivec instructions that use bit 31 (Rc) as an opcode - * bit but also use bit 21 as an actual Rc bit. In general, thse pairs - * come from different versions of the ISA, so we must also support a - * pair of flags for each instruction. - */ -#define GEN_VXRFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1) \ -static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ -{ \ - if ((Rc(ctx->opcode) == 0) && \ - ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \ - if (Rc21(ctx->opcode) == 0) { \ - gen_##name0(ctx); \ - } else { \ - gen_##name0##_(ctx); \ - } \ - } else if ((Rc(ctx->opcode) == 1) && \ - ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \ - if (Rc21(ctx->opcode) == 0) { \ - gen_##name1(ctx); \ - } else { \ - gen_##name1##_(ctx); \ - } \ - } else { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - } \ -} - -GEN_VXRFORM(vcmpequb, 3, 0) -GEN_VXRFORM(vcmpequh, 3, 1) -GEN_VXRFORM(vcmpequw, 3, 2) -GEN_VXRFORM(vcmpequd, 3, 3) -GEN_VXRFORM(vcmpgtsb, 3, 12) -GEN_VXRFORM(vcmpgtsh, 3, 13) -GEN_VXRFORM(vcmpgtsw, 3, 14) -GEN_VXRFORM(vcmpgtsd, 3, 15) -GEN_VXRFORM(vcmpgtub, 3, 8) -GEN_VXRFORM(vcmpgtuh, 3, 9) -GEN_VXRFORM(vcmpgtuw, 3, 10) -GEN_VXRFORM(vcmpgtud, 3, 11) -GEN_VXRFORM(vcmpeqfp, 3, 3) -GEN_VXRFORM(vcmpgefp, 3, 7) -GEN_VXRFORM(vcmpgtfp, 3, 11) -GEN_VXRFORM(vcmpbfp, 3, 15) - -GEN_VXRFORM_DUAL(vcmpeqfp, PPC_ALTIVEC, PPC_NONE, \ - vcmpequd, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \ - vcmpgtsd, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXRFORM_DUAL(vcmpgtfp, PPC_ALTIVEC, PPC_NONE, \ - vcmpgtud, PPC_NONE, PPC2_ALTIVEC_207) - -#define GEN_VXFORM_SIMM(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ - { \ - TCGv_ptr rd; \ - TCGv_i32 simm; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - simm = tcg_const_i32(SIMM5(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name (rd, simm); \ - tcg_temp_free_i32(simm); \ - tcg_temp_free_ptr(rd); \ - } - -GEN_VXFORM_SIMM(vspltisb, 6, 12); -GEN_VXFORM_SIMM(vspltish, 6, 13); -GEN_VXFORM_SIMM(vspltisw, 6, 14); - -#define GEN_VXFORM_NOA(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ - { \ - TCGv_ptr rb, rd; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - rb = gen_avr_ptr(rB(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name (rd, rb); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ - } - -#define GEN_VXFORM_NOA_ENV(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ - { \ - TCGv_ptr rb, rd; \ - \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - rb = gen_avr_ptr(rB(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name(cpu_env, rd, rb); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ - } - -GEN_VXFORM_NOA(vupkhsb, 7, 8); -GEN_VXFORM_NOA(vupkhsh, 7, 9); -GEN_VXFORM_NOA(vupkhsw, 7, 25); -GEN_VXFORM_NOA(vupklsb, 7, 10); -GEN_VXFORM_NOA(vupklsh, 7, 11); -GEN_VXFORM_NOA(vupklsw, 7, 27); -GEN_VXFORM_NOA(vupkhpx, 7, 13); -GEN_VXFORM_NOA(vupklpx, 7, 15); -GEN_VXFORM_NOA_ENV(vrefp, 5, 4); -GEN_VXFORM_NOA_ENV(vrsqrtefp, 5, 5); -GEN_VXFORM_NOA_ENV(vexptefp, 5, 6); -GEN_VXFORM_NOA_ENV(vlogefp, 5, 7); -GEN_VXFORM_NOA_ENV(vrfim, 5, 11); -GEN_VXFORM_NOA_ENV(vrfin, 5, 8); -GEN_VXFORM_NOA_ENV(vrfip, 5, 10); -GEN_VXFORM_NOA_ENV(vrfiz, 5, 9); - -#define GEN_VXFORM_SIMM(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ - { \ - TCGv_ptr rd; \ - TCGv_i32 simm; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - simm = tcg_const_i32(SIMM5(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name (rd, simm); \ - tcg_temp_free_i32(simm); \ - tcg_temp_free_ptr(rd); \ - } - -#define GEN_VXFORM_UIMM(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ - { \ - TCGv_ptr rb, rd; \ - TCGv_i32 uimm; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - uimm = tcg_const_i32(UIMM5(ctx->opcode)); \ - rb = gen_avr_ptr(rB(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name (rd, rb, uimm); \ - tcg_temp_free_i32(uimm); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ - } - -#define GEN_VXFORM_UIMM_ENV(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ - { \ - TCGv_ptr rb, rd; \ - TCGv_i32 uimm; \ - \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - uimm = tcg_const_i32(UIMM5(ctx->opcode)); \ - rb = gen_avr_ptr(rB(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name(cpu_env, rd, rb, uimm); \ - tcg_temp_free_i32(uimm); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ - } - -GEN_VXFORM_UIMM(vspltb, 6, 8); -GEN_VXFORM_UIMM(vsplth, 6, 9); -GEN_VXFORM_UIMM(vspltw, 6, 10); -GEN_VXFORM_UIMM_ENV(vcfux, 5, 12); -GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13); -GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14); -GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15); - -static void gen_vsldoi(DisasContext *ctx) -{ - TCGv_ptr ra, rb, rd; - TCGv_i32 sh; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - ra = gen_avr_ptr(rA(ctx->opcode)); - rb = gen_avr_ptr(rB(ctx->opcode)); - rd = gen_avr_ptr(rD(ctx->opcode)); - sh = tcg_const_i32(VSH(ctx->opcode)); - gen_helper_vsldoi (rd, ra, rb, sh); - tcg_temp_free_ptr(ra); - tcg_temp_free_ptr(rb); - tcg_temp_free_ptr(rd); - tcg_temp_free_i32(sh); -} - -#define GEN_VAFORM_PAIRED(name0, name1, opc2) \ -static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ - { \ - TCGv_ptr ra, rb, rc, rd; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - ra = gen_avr_ptr(rA(ctx->opcode)); \ - rb = gen_avr_ptr(rB(ctx->opcode)); \ - rc = gen_avr_ptr(rC(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - if (Rc(ctx->opcode)) { \ - gen_helper_##name1(cpu_env, rd, ra, rb, rc); \ - } else { \ - gen_helper_##name0(cpu_env, rd, ra, rb, rc); \ - } \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rc); \ - tcg_temp_free_ptr(rd); \ - } - -GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16) - -static void gen_vmladduhm(DisasContext *ctx) -{ - TCGv_ptr ra, rb, rc, rd; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - ra = gen_avr_ptr(rA(ctx->opcode)); - rb = gen_avr_ptr(rB(ctx->opcode)); - rc = gen_avr_ptr(rC(ctx->opcode)); - rd = gen_avr_ptr(rD(ctx->opcode)); - gen_helper_vmladduhm(rd, ra, rb, rc); - tcg_temp_free_ptr(ra); - tcg_temp_free_ptr(rb); - tcg_temp_free_ptr(rc); - tcg_temp_free_ptr(rd); -} - -GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18) -GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19) -GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20) -GEN_VAFORM_PAIRED(vsel, vperm, 21) -GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) #if defined(TARGET_PPC64) static void gen_maddld(DisasContext *ctx) @@ -6736,115 +6042,6 @@ static void gen_maddhd_maddhdu(DisasContext *ctx) } #endif /* defined(TARGET_PPC64) */ -GEN_VXFORM_NOA(vclzb, 1, 28) -GEN_VXFORM_NOA(vclzh, 1, 29) -GEN_VXFORM_NOA(vclzw, 1, 30) -GEN_VXFORM_NOA(vclzd, 1, 31) -GEN_VXFORM_NOA(vpopcntb, 1, 28) -GEN_VXFORM_NOA(vpopcnth, 1, 29) -GEN_VXFORM_NOA(vpopcntw, 1, 30) -GEN_VXFORM_NOA(vpopcntd, 1, 31) -GEN_VXFORM_DUAL(vclzb, PPC_NONE, PPC2_ALTIVEC_207, \ - vpopcntb, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM_DUAL(vclzh, PPC_NONE, PPC2_ALTIVEC_207, \ - vpopcnth, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM_DUAL(vclzw, PPC_NONE, PPC2_ALTIVEC_207, \ - vpopcntw, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM_DUAL(vclzd, PPC_NONE, PPC2_ALTIVEC_207, \ - vpopcntd, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM(vbpermq, 6, 21); -GEN_VXFORM_NOA(vgbbd, 6, 20); -GEN_VXFORM(vpmsumb, 4, 16) -GEN_VXFORM(vpmsumh, 4, 17) -GEN_VXFORM(vpmsumw, 4, 18) -GEN_VXFORM(vpmsumd, 4, 19) - -#define GEN_BCD(op) \ -static void gen_##op(DisasContext *ctx) \ -{ \ - TCGv_ptr ra, rb, rd; \ - TCGv_i32 ps; \ - \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - \ - ra = gen_avr_ptr(rA(ctx->opcode)); \ - rb = gen_avr_ptr(rB(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - \ - ps = tcg_const_i32((ctx->opcode & 0x200) != 0); \ - \ - gen_helper_##op(cpu_crf[6], rd, ra, rb, ps); \ - \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ - tcg_temp_free_i32(ps); \ -} - -GEN_BCD(bcdadd) -GEN_BCD(bcdsub) - -GEN_VXFORM_DUAL(vsububm, PPC_ALTIVEC, PPC_NONE, \ - bcdadd, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM_DUAL(vsububs, PPC_ALTIVEC, PPC_NONE, \ - bcdadd, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM_DUAL(vsubuhm, PPC_ALTIVEC, PPC_NONE, \ - bcdsub, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM_DUAL(vsubuhs, PPC_ALTIVEC, PPC_NONE, \ - bcdsub, PPC_NONE, PPC2_ALTIVEC_207) - -static void gen_vsbox(DisasContext *ctx) -{ - TCGv_ptr ra, rd; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - ra = gen_avr_ptr(rA(ctx->opcode)); - rd = gen_avr_ptr(rD(ctx->opcode)); - gen_helper_vsbox(rd, ra); - tcg_temp_free_ptr(ra); - tcg_temp_free_ptr(rd); -} - -GEN_VXFORM(vcipher, 4, 20) -GEN_VXFORM(vcipherlast, 4, 20) -GEN_VXFORM(vncipher, 4, 21) -GEN_VXFORM(vncipherlast, 4, 21) - -GEN_VXFORM_DUAL(vcipher, PPC_NONE, PPC2_ALTIVEC_207, - vcipherlast, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM_DUAL(vncipher, PPC_NONE, PPC2_ALTIVEC_207, - vncipherlast, PPC_NONE, PPC2_ALTIVEC_207) - -#define VSHASIGMA(op) \ -static void gen_##op(DisasContext *ctx) \ -{ \ - TCGv_ptr ra, rd; \ - TCGv_i32 st_six; \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - ra = gen_avr_ptr(rA(ctx->opcode)); \ - rd = gen_avr_ptr(rD(ctx->opcode)); \ - st_six = tcg_const_i32(rB(ctx->opcode)); \ - gen_helper_##op(rd, ra, st_six); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rd); \ - tcg_temp_free_i32(st_six); \ -} - -VSHASIGMA(vshasigmaw) -VSHASIGMA(vshasigmad) - -GEN_VXFORM3(vpermxor, 22, 0xFF) -GEN_VXFORM_DUAL(vsldoi, PPC_ALTIVEC, PPC_NONE, - vpermxor, PPC_NONE, PPC2_ALTIVEC_207) - /*** VSX extension ***/ static inline TCGv_i64 cpu_vsrh(int n) @@ -8165,266 +7362,7 @@ GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C), #include "translate/fp-ops.c" -#undef GEN_VR_LDX -#undef GEN_VR_STX -#undef GEN_VR_LVE -#undef GEN_VR_STVE -#define GEN_VR_LDX(name, opc2, opc3) \ -GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) -#define GEN_VR_STX(name, opc2, opc3) \ -GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) -#define GEN_VR_LVE(name, opc2, opc3) \ - GEN_HANDLER(lve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) -#define GEN_VR_STVE(name, opc2, opc3) \ - GEN_HANDLER(stve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) -GEN_VR_LDX(lvx, 0x07, 0x03), -GEN_VR_LDX(lvxl, 0x07, 0x0B), -GEN_VR_LVE(bx, 0x07, 0x00), -GEN_VR_LVE(hx, 0x07, 0x01), -GEN_VR_LVE(wx, 0x07, 0x02), -GEN_VR_STX(svx, 0x07, 0x07), -GEN_VR_STX(svxl, 0x07, 0x0F), -GEN_VR_STVE(bx, 0x07, 0x04), -GEN_VR_STVE(hx, 0x07, 0x05), -GEN_VR_STVE(wx, 0x07, 0x06), - -#undef GEN_VX_LOGICAL -#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3) \ -GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) - -#undef GEN_VX_LOGICAL_207 -#define GEN_VX_LOGICAL_207(name, tcg_op, opc2, opc3) \ -GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207) - -GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16), -GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17), -GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18), -GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19), -GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20), -GEN_VX_LOGICAL_207(veqv, tcg_gen_eqv_i64, 2, 26), -GEN_VX_LOGICAL_207(vnand, tcg_gen_nand_i64, 2, 22), -GEN_VX_LOGICAL_207(vorc, tcg_gen_orc_i64, 2, 21), - -#undef GEN_VXFORM -#define GEN_VXFORM(name, opc2, opc3) \ -GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) - -#undef GEN_VXFORM_207 -#define GEN_VXFORM_207(name, opc2, opc3) \ -GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207) - -#undef GEN_VXFORM_DUAL -#define GEN_VXFORM_DUAL(name0, name1, opc2, opc3, type0, type1) \ -GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, type0, type1) - -#undef GEN_VXRFORM_DUAL -#define GEN_VXRFORM_DUAL(name0, name1, opc2, opc3, tp0, tp1) \ -GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, tp0, tp1), \ -GEN_HANDLER_E(name0##_##name1, 0x4, opc2, (opc3 | 0x10), 0x00000000, tp0, tp1), - -GEN_VXFORM(vaddubm, 0, 0), -GEN_VXFORM(vadduhm, 0, 1), -GEN_VXFORM(vadduwm, 0, 2), -GEN_VXFORM_207(vaddudm, 0, 3), -GEN_VXFORM_DUAL(vsububm, bcdadd, 0, 16, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_DUAL(vsubuhm, bcdsub, 0, 17, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM(vsubuwm, 0, 18), -GEN_VXFORM_207(vsubudm, 0, 19), -GEN_VXFORM(vmaxub, 1, 0), -GEN_VXFORM(vmaxuh, 1, 1), -GEN_VXFORM(vmaxuw, 1, 2), -GEN_VXFORM_207(vmaxud, 1, 3), -GEN_VXFORM(vmaxsb, 1, 4), -GEN_VXFORM(vmaxsh, 1, 5), -GEN_VXFORM(vmaxsw, 1, 6), -GEN_VXFORM_207(vmaxsd, 1, 7), -GEN_VXFORM(vminub, 1, 8), -GEN_VXFORM(vminuh, 1, 9), -GEN_VXFORM(vminuw, 1, 10), -GEN_VXFORM_207(vminud, 1, 11), -GEN_VXFORM(vminsb, 1, 12), -GEN_VXFORM(vminsh, 1, 13), -GEN_VXFORM(vminsw, 1, 14), -GEN_VXFORM_207(vminsd, 1, 15), -GEN_VXFORM(vavgub, 1, 16), -GEN_VXFORM(vavguh, 1, 17), -GEN_VXFORM(vavguw, 1, 18), -GEN_VXFORM(vavgsb, 1, 20), -GEN_VXFORM(vavgsh, 1, 21), -GEN_VXFORM(vavgsw, 1, 22), -GEN_VXFORM(vmrghb, 6, 0), -GEN_VXFORM(vmrghh, 6, 1), -GEN_VXFORM(vmrghw, 6, 2), -GEN_VXFORM(vmrglb, 6, 4), -GEN_VXFORM(vmrglh, 6, 5), -GEN_VXFORM(vmrglw, 6, 6), -GEN_VXFORM_207(vmrgew, 6, 30), -GEN_VXFORM_207(vmrgow, 6, 26), -GEN_VXFORM(vmuloub, 4, 0), -GEN_VXFORM(vmulouh, 4, 1), -GEN_VXFORM_DUAL(vmulouw, vmuluwm, 4, 2, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM(vmulosb, 4, 4), -GEN_VXFORM(vmulosh, 4, 5), -GEN_VXFORM_207(vmulosw, 4, 6), -GEN_VXFORM(vmuleub, 4, 8), -GEN_VXFORM(vmuleuh, 4, 9), -GEN_VXFORM_207(vmuleuw, 4, 10), -GEN_VXFORM(vmulesb, 4, 12), -GEN_VXFORM(vmulesh, 4, 13), -GEN_VXFORM_207(vmulesw, 4, 14), -GEN_VXFORM(vslb, 2, 4), -GEN_VXFORM(vslh, 2, 5), -GEN_VXFORM(vslw, 2, 6), -GEN_VXFORM_207(vsld, 2, 23), -GEN_VXFORM(vsrb, 2, 8), -GEN_VXFORM(vsrh, 2, 9), -GEN_VXFORM(vsrw, 2, 10), -GEN_VXFORM_207(vsrd, 2, 27), -GEN_VXFORM(vsrab, 2, 12), -GEN_VXFORM(vsrah, 2, 13), -GEN_VXFORM(vsraw, 2, 14), -GEN_VXFORM_207(vsrad, 2, 15), -GEN_VXFORM(vslo, 6, 16), -GEN_VXFORM(vsro, 6, 17), -GEN_VXFORM(vaddcuw, 0, 6), -GEN_VXFORM(vsubcuw, 0, 22), -GEN_VXFORM(vaddubs, 0, 8), -GEN_VXFORM(vadduhs, 0, 9), -GEN_VXFORM(vadduws, 0, 10), -GEN_VXFORM(vaddsbs, 0, 12), -GEN_VXFORM(vaddshs, 0, 13), -GEN_VXFORM(vaddsws, 0, 14), -GEN_VXFORM_DUAL(vsububs, bcdadd, 0, 24, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_DUAL(vsubuhs, bcdsub, 0, 25, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM(vsubuws, 0, 26), -GEN_VXFORM(vsubsbs, 0, 28), -GEN_VXFORM(vsubshs, 0, 29), -GEN_VXFORM(vsubsws, 0, 30), -GEN_VXFORM_207(vadduqm, 0, 4), -GEN_VXFORM_207(vaddcuq, 0, 5), -GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207), -GEN_VXFORM_207(vsubuqm, 0, 20), -GEN_VXFORM_207(vsubcuq, 0, 21), -GEN_VXFORM_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207), -GEN_VXFORM(vrlb, 2, 0), -GEN_VXFORM(vrlh, 2, 1), -GEN_VXFORM(vrlw, 2, 2), -GEN_VXFORM_207(vrld, 2, 3), -GEN_VXFORM(vsl, 2, 7), -GEN_VXFORM(vsr, 2, 11), -GEN_VXFORM(vpkuhum, 7, 0), -GEN_VXFORM(vpkuwum, 7, 1), -GEN_VXFORM_207(vpkudum, 7, 17), -GEN_VXFORM(vpkuhus, 7, 2), -GEN_VXFORM(vpkuwus, 7, 3), -GEN_VXFORM_207(vpkudus, 7, 19), -GEN_VXFORM(vpkshus, 7, 4), -GEN_VXFORM(vpkswus, 7, 5), -GEN_VXFORM_207(vpksdus, 7, 21), -GEN_VXFORM(vpkshss, 7, 6), -GEN_VXFORM(vpkswss, 7, 7), -GEN_VXFORM_207(vpksdss, 7, 23), -GEN_VXFORM(vpkpx, 7, 12), -GEN_VXFORM(vsum4ubs, 4, 24), -GEN_VXFORM(vsum4sbs, 4, 28), -GEN_VXFORM(vsum4shs, 4, 25), -GEN_VXFORM(vsum2sws, 4, 26), -GEN_VXFORM(vsumsws, 4, 30), -GEN_VXFORM(vaddfp, 5, 0), -GEN_VXFORM(vsubfp, 5, 1), -GEN_VXFORM(vmaxfp, 5, 16), -GEN_VXFORM(vminfp, 5, 17), - -#undef GEN_VXRFORM1 -#undef GEN_VXRFORM -#define GEN_VXRFORM1(opname, name, str, opc2, opc3) \ - GEN_HANDLER2(name, str, 0x4, opc2, opc3, 0x00000000, PPC_ALTIVEC), -#define GEN_VXRFORM(name, opc2, opc3) \ - GEN_VXRFORM1(name, name, #name, opc2, opc3) \ - GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4))) -GEN_VXRFORM(vcmpequb, 3, 0) -GEN_VXRFORM(vcmpequh, 3, 1) -GEN_VXRFORM(vcmpequw, 3, 2) -GEN_VXRFORM(vcmpgtsb, 3, 12) -GEN_VXRFORM(vcmpgtsh, 3, 13) -GEN_VXRFORM(vcmpgtsw, 3, 14) -GEN_VXRFORM(vcmpgtub, 3, 8) -GEN_VXRFORM(vcmpgtuh, 3, 9) -GEN_VXRFORM(vcmpgtuw, 3, 10) -GEN_VXRFORM_DUAL(vcmpeqfp, vcmpequd, 3, 3, PPC_ALTIVEC, PPC_NONE) -GEN_VXRFORM(vcmpgefp, 3, 7) -GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE) -GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE) - -#undef GEN_VXFORM_SIMM -#define GEN_VXFORM_SIMM(name, opc2, opc3) \ - GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) -GEN_VXFORM_SIMM(vspltisb, 6, 12), -GEN_VXFORM_SIMM(vspltish, 6, 13), -GEN_VXFORM_SIMM(vspltisw, 6, 14), - -#undef GEN_VXFORM_NOA -#define GEN_VXFORM_NOA(name, opc2, opc3) \ - GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC) -GEN_VXFORM_NOA(vupkhsb, 7, 8), -GEN_VXFORM_NOA(vupkhsh, 7, 9), -GEN_VXFORM_207(vupkhsw, 7, 25), -GEN_VXFORM_NOA(vupklsb, 7, 10), -GEN_VXFORM_NOA(vupklsh, 7, 11), -GEN_VXFORM_207(vupklsw, 7, 27), -GEN_VXFORM_NOA(vupkhpx, 7, 13), -GEN_VXFORM_NOA(vupklpx, 7, 15), -GEN_VXFORM_NOA(vrefp, 5, 4), -GEN_VXFORM_NOA(vrsqrtefp, 5, 5), -GEN_VXFORM_NOA(vexptefp, 5, 6), -GEN_VXFORM_NOA(vlogefp, 5, 7), -GEN_VXFORM_NOA(vrfim, 5, 11), -GEN_VXFORM_NOA(vrfin, 5, 8), -GEN_VXFORM_NOA(vrfip, 5, 10), -GEN_VXFORM_NOA(vrfiz, 5, 9), - -#undef GEN_VXFORM_UIMM -#define GEN_VXFORM_UIMM(name, opc2, opc3) \ - GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) -GEN_VXFORM_UIMM(vspltb, 6, 8), -GEN_VXFORM_UIMM(vsplth, 6, 9), -GEN_VXFORM_UIMM(vspltw, 6, 10), -GEN_VXFORM_UIMM(vcfux, 5, 12), -GEN_VXFORM_UIMM(vcfsx, 5, 13), -GEN_VXFORM_UIMM(vctuxs, 5, 14), -GEN_VXFORM_UIMM(vctsxs, 5, 15), - -#undef GEN_VAFORM_PAIRED -#define GEN_VAFORM_PAIRED(name0, name1, opc2) \ - GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC) -GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16), -GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18), -GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19), -GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20), -GEN_VAFORM_PAIRED(vsel, vperm, 21), -GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), - -GEN_VXFORM_DUAL(vclzb, vpopcntb, 1, 28, PPC_NONE, PPC2_ALTIVEC_207), -GEN_VXFORM_DUAL(vclzh, vpopcnth, 1, 29, PPC_NONE, PPC2_ALTIVEC_207), -GEN_VXFORM_DUAL(vclzw, vpopcntw, 1, 30, PPC_NONE, PPC2_ALTIVEC_207), -GEN_VXFORM_DUAL(vclzd, vpopcntd, 1, 31, PPC_NONE, PPC2_ALTIVEC_207), - -GEN_VXFORM_207(vbpermq, 6, 21), -GEN_VXFORM_207(vgbbd, 6, 20), -GEN_VXFORM_207(vpmsumb, 4, 16), -GEN_VXFORM_207(vpmsumh, 4, 17), -GEN_VXFORM_207(vpmsumw, 4, 18), -GEN_VXFORM_207(vpmsumd, 4, 19), - -GEN_VXFORM_207(vsbox, 4, 23), - -GEN_VXFORM_DUAL(vcipher, vcipherlast, 4, 20, PPC_NONE, PPC2_ALTIVEC_207), -GEN_VXFORM_DUAL(vncipher, vncipherlast, 4, 21, PPC_NONE, PPC2_ALTIVEC_207), - -GEN_VXFORM_207(vshasigmaw, 1, 26), -GEN_VXFORM_207(vshasigmad, 1, 27), - -GEN_VXFORM_DUAL(vsldoi, vpermxor, 22, 0xFF, PPC_ALTIVEC, PPC_NONE), +#include "translate/vmx-ops.c" GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxsiwax, 0x1F, 0x0C, 0x02, 0, PPC_NONE, PPC2_VSX207), diff --git a/target-ppc/translate/vmx-impl.c b/target-ppc/translate/vmx-impl.c new file mode 100644 index 0000000000..110e19c88b --- /dev/null +++ b/target-ppc/translate/vmx-impl.c @@ -0,0 +1,829 @@ +/* + * translate/vmx-impl.c + * + * Altivec/VMX translation + */ + +/*** Altivec vector extension ***/ +/* Altivec registers moves */ + +static inline TCGv_ptr gen_avr_ptr(int reg) +{ + TCGv_ptr r = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, avr[reg])); + return r; +} + +#define GEN_VR_LDX(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_INT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + tcg_gen_andi_tl(EA, EA, ~0xf); \ + /* We only need to swap high and low halves. gen_qemu_ld64 does necessary \ + 64-bit byteswap already. */ \ + if (ctx->le_mode) { \ + gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + tcg_gen_addi_tl(EA, EA, 8); \ + gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + } else { \ + gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + tcg_gen_addi_tl(EA, EA, 8); \ + gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + } \ + tcg_temp_free(EA); \ +} + +#define GEN_VR_STX(name, opc2, opc3) \ +static void gen_st##name(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_INT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + tcg_gen_andi_tl(EA, EA, ~0xf); \ + /* We only need to swap high and low halves. gen_qemu_st64 does necessary \ + 64-bit byteswap already. */ \ + if (ctx->le_mode) { \ + gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + tcg_gen_addi_tl(EA, EA, 8); \ + gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + } else { \ + gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + tcg_gen_addi_tl(EA, EA, 8); \ + gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + } \ + tcg_temp_free(EA); \ +} + +#define GEN_VR_LVE(name, opc2, opc3, size) \ +static void gen_lve##name(DisasContext *ctx) \ + { \ + TCGv EA; \ + TCGv_ptr rs; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_INT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + if (size > 1) { \ + tcg_gen_andi_tl(EA, EA, ~(size - 1)); \ + } \ + rs = gen_avr_ptr(rS(ctx->opcode)); \ + gen_helper_lve##name(cpu_env, rs, EA); \ + tcg_temp_free(EA); \ + tcg_temp_free_ptr(rs); \ + } + +#define GEN_VR_STVE(name, opc2, opc3, size) \ +static void gen_stve##name(DisasContext *ctx) \ + { \ + TCGv EA; \ + TCGv_ptr rs; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_INT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + if (size > 1) { \ + tcg_gen_andi_tl(EA, EA, ~(size - 1)); \ + } \ + rs = gen_avr_ptr(rS(ctx->opcode)); \ + gen_helper_stve##name(cpu_env, rs, EA); \ + tcg_temp_free(EA); \ + tcg_temp_free_ptr(rs); \ + } + +GEN_VR_LDX(lvx, 0x07, 0x03); +/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */ +GEN_VR_LDX(lvxl, 0x07, 0x0B); + +GEN_VR_LVE(bx, 0x07, 0x00, 1); +GEN_VR_LVE(hx, 0x07, 0x01, 2); +GEN_VR_LVE(wx, 0x07, 0x02, 4); + +GEN_VR_STX(svx, 0x07, 0x07); +/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */ +GEN_VR_STX(svxl, 0x07, 0x0F); + +GEN_VR_STVE(bx, 0x07, 0x04, 1); +GEN_VR_STVE(hx, 0x07, 0x05, 2); +GEN_VR_STVE(wx, 0x07, 0x06, 4); + +static void gen_lvsl(DisasContext *ctx) +{ + TCGv_ptr rd; + TCGv EA; + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + rd = gen_avr_ptr(rD(ctx->opcode)); + gen_helper_lvsl(rd, EA); + tcg_temp_free(EA); + tcg_temp_free_ptr(rd); +} + +static void gen_lvsr(DisasContext *ctx) +{ + TCGv_ptr rd; + TCGv EA; + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + rd = gen_avr_ptr(rD(ctx->opcode)); + gen_helper_lvsr(rd, EA); + tcg_temp_free(EA); + tcg_temp_free_ptr(rd); +} + +static void gen_mfvscr(DisasContext *ctx) +{ + TCGv_i32 t; + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + tcg_gen_movi_i64(cpu_avrh[rD(ctx->opcode)], 0); + t = tcg_temp_new_i32(); + tcg_gen_ld_i32(t, cpu_env, offsetof(CPUPPCState, vscr)); + tcg_gen_extu_i32_i64(cpu_avrl[rD(ctx->opcode)], t); + tcg_temp_free_i32(t); +} + +static void gen_mtvscr(DisasContext *ctx) +{ + TCGv_ptr p; + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + p = gen_avr_ptr(rB(ctx->opcode)); + gen_helper_mtvscr(cpu_env, p); + tcg_temp_free_ptr(p); +} + +/* Logical operations */ +#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + tcg_op(cpu_avrh[rD(ctx->opcode)], cpu_avrh[rA(ctx->opcode)], cpu_avrh[rB(ctx->opcode)]); \ + tcg_op(cpu_avrl[rD(ctx->opcode)], cpu_avrl[rA(ctx->opcode)], cpu_avrl[rB(ctx->opcode)]); \ +} + +GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16); +GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17); +GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18); +GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19); +GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20); +GEN_VX_LOGICAL(veqv, tcg_gen_eqv_i64, 2, 26); +GEN_VX_LOGICAL(vnand, tcg_gen_nand_i64, 2, 22); +GEN_VX_LOGICAL(vorc, tcg_gen_orc_i64, 2, 21); + +#define GEN_VXFORM(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + TCGv_ptr ra, rb, rd; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + ra = gen_avr_ptr(rA(ctx->opcode)); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name (rd, ra, rb); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ +} + +#define GEN_VXFORM_ENV(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + TCGv_ptr ra, rb, rd; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + ra = gen_avr_ptr(rA(ctx->opcode)); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name(cpu_env, rd, ra, rb); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ +} + +#define GEN_VXFORM3(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + TCGv_ptr ra, rb, rc, rd; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + ra = gen_avr_ptr(rA(ctx->opcode)); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rc = gen_avr_ptr(rC(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name(rd, ra, rb, rc); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rc); \ + tcg_temp_free_ptr(rd); \ +} + +/* + * Support for Altivec instruction pairs that use bit 31 (Rc) as + * an opcode bit. In general, these pairs come from different + * versions of the ISA, so we must also support a pair of flags for + * each instruction. + */ +#define GEN_VXFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1) \ +static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ +{ \ + if ((Rc(ctx->opcode) == 0) && \ + ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \ + gen_##name0(ctx); \ + } else if ((Rc(ctx->opcode) == 1) && \ + ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \ + gen_##name1(ctx); \ + } else { \ + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ + } \ +} + +GEN_VXFORM(vaddubm, 0, 0); +GEN_VXFORM(vadduhm, 0, 1); +GEN_VXFORM(vadduwm, 0, 2); +GEN_VXFORM(vaddudm, 0, 3); +GEN_VXFORM(vsububm, 0, 16); +GEN_VXFORM(vsubuhm, 0, 17); +GEN_VXFORM(vsubuwm, 0, 18); +GEN_VXFORM(vsubudm, 0, 19); +GEN_VXFORM(vmaxub, 1, 0); +GEN_VXFORM(vmaxuh, 1, 1); +GEN_VXFORM(vmaxuw, 1, 2); +GEN_VXFORM(vmaxud, 1, 3); +GEN_VXFORM(vmaxsb, 1, 4); +GEN_VXFORM(vmaxsh, 1, 5); +GEN_VXFORM(vmaxsw, 1, 6); +GEN_VXFORM(vmaxsd, 1, 7); +GEN_VXFORM(vminub, 1, 8); +GEN_VXFORM(vminuh, 1, 9); +GEN_VXFORM(vminuw, 1, 10); +GEN_VXFORM(vminud, 1, 11); +GEN_VXFORM(vminsb, 1, 12); +GEN_VXFORM(vminsh, 1, 13); +GEN_VXFORM(vminsw, 1, 14); +GEN_VXFORM(vminsd, 1, 15); +GEN_VXFORM(vavgub, 1, 16); +GEN_VXFORM(vavguh, 1, 17); +GEN_VXFORM(vavguw, 1, 18); +GEN_VXFORM(vavgsb, 1, 20); +GEN_VXFORM(vavgsh, 1, 21); +GEN_VXFORM(vavgsw, 1, 22); +GEN_VXFORM(vmrghb, 6, 0); +GEN_VXFORM(vmrghh, 6, 1); +GEN_VXFORM(vmrghw, 6, 2); +GEN_VXFORM(vmrglb, 6, 4); +GEN_VXFORM(vmrglh, 6, 5); +GEN_VXFORM(vmrglw, 6, 6); + +static void gen_vmrgew(DisasContext *ctx) +{ + TCGv_i64 tmp; + int VT, VA, VB; + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + VT = rD(ctx->opcode); + VA = rA(ctx->opcode); + VB = rB(ctx->opcode); + tmp = tcg_temp_new_i64(); + tcg_gen_shri_i64(tmp, cpu_avrh[VB], 32); + tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VA], tmp, 0, 32); + tcg_gen_shri_i64(tmp, cpu_avrl[VB], 32); + tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VA], tmp, 0, 32); + tcg_temp_free_i64(tmp); +} + +static void gen_vmrgow(DisasContext *ctx) +{ + int VT, VA, VB; + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + VT = rD(ctx->opcode); + VA = rA(ctx->opcode); + VB = rB(ctx->opcode); + + tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VB], cpu_avrh[VA], 32, 32); + tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VB], cpu_avrl[VA], 32, 32); +} + +GEN_VXFORM(vmuloub, 4, 0); +GEN_VXFORM(vmulouh, 4, 1); +GEN_VXFORM(vmulouw, 4, 2); +GEN_VXFORM(vmuluwm, 4, 2); +GEN_VXFORM_DUAL(vmulouw, PPC_ALTIVEC, PPC_NONE, + vmuluwm, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM(vmulosb, 4, 4); +GEN_VXFORM(vmulosh, 4, 5); +GEN_VXFORM(vmulosw, 4, 6); +GEN_VXFORM(vmuleub, 4, 8); +GEN_VXFORM(vmuleuh, 4, 9); +GEN_VXFORM(vmuleuw, 4, 10); +GEN_VXFORM(vmulesb, 4, 12); +GEN_VXFORM(vmulesh, 4, 13); +GEN_VXFORM(vmulesw, 4, 14); +GEN_VXFORM(vslb, 2, 4); +GEN_VXFORM(vslh, 2, 5); +GEN_VXFORM(vslw, 2, 6); +GEN_VXFORM(vsld, 2, 23); +GEN_VXFORM(vsrb, 2, 8); +GEN_VXFORM(vsrh, 2, 9); +GEN_VXFORM(vsrw, 2, 10); +GEN_VXFORM(vsrd, 2, 27); +GEN_VXFORM(vsrab, 2, 12); +GEN_VXFORM(vsrah, 2, 13); +GEN_VXFORM(vsraw, 2, 14); +GEN_VXFORM(vsrad, 2, 15); +GEN_VXFORM(vslo, 6, 16); +GEN_VXFORM(vsro, 6, 17); +GEN_VXFORM(vaddcuw, 0, 6); +GEN_VXFORM(vsubcuw, 0, 22); +GEN_VXFORM_ENV(vaddubs, 0, 8); +GEN_VXFORM_ENV(vadduhs, 0, 9); +GEN_VXFORM_ENV(vadduws, 0, 10); +GEN_VXFORM_ENV(vaddsbs, 0, 12); +GEN_VXFORM_ENV(vaddshs, 0, 13); +GEN_VXFORM_ENV(vaddsws, 0, 14); +GEN_VXFORM_ENV(vsububs, 0, 24); +GEN_VXFORM_ENV(vsubuhs, 0, 25); +GEN_VXFORM_ENV(vsubuws, 0, 26); +GEN_VXFORM_ENV(vsubsbs, 0, 28); +GEN_VXFORM_ENV(vsubshs, 0, 29); +GEN_VXFORM_ENV(vsubsws, 0, 30); +GEN_VXFORM(vadduqm, 0, 4); +GEN_VXFORM(vaddcuq, 0, 5); +GEN_VXFORM3(vaddeuqm, 30, 0); +GEN_VXFORM3(vaddecuq, 30, 0); +GEN_VXFORM_DUAL(vaddeuqm, PPC_NONE, PPC2_ALTIVEC_207, \ + vaddecuq, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM(vsubuqm, 0, 20); +GEN_VXFORM(vsubcuq, 0, 21); +GEN_VXFORM3(vsubeuqm, 31, 0); +GEN_VXFORM3(vsubecuq, 31, 0); +GEN_VXFORM_DUAL(vsubeuqm, PPC_NONE, PPC2_ALTIVEC_207, \ + vsubecuq, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM(vrlb, 2, 0); +GEN_VXFORM(vrlh, 2, 1); +GEN_VXFORM(vrlw, 2, 2); +GEN_VXFORM(vrld, 2, 3); +GEN_VXFORM(vsl, 2, 7); +GEN_VXFORM(vsr, 2, 11); +GEN_VXFORM_ENV(vpkuhum, 7, 0); +GEN_VXFORM_ENV(vpkuwum, 7, 1); +GEN_VXFORM_ENV(vpkudum, 7, 17); +GEN_VXFORM_ENV(vpkuhus, 7, 2); +GEN_VXFORM_ENV(vpkuwus, 7, 3); +GEN_VXFORM_ENV(vpkudus, 7, 19); +GEN_VXFORM_ENV(vpkshus, 7, 4); +GEN_VXFORM_ENV(vpkswus, 7, 5); +GEN_VXFORM_ENV(vpksdus, 7, 21); +GEN_VXFORM_ENV(vpkshss, 7, 6); +GEN_VXFORM_ENV(vpkswss, 7, 7); +GEN_VXFORM_ENV(vpksdss, 7, 23); +GEN_VXFORM(vpkpx, 7, 12); +GEN_VXFORM_ENV(vsum4ubs, 4, 24); +GEN_VXFORM_ENV(vsum4sbs, 4, 28); +GEN_VXFORM_ENV(vsum4shs, 4, 25); +GEN_VXFORM_ENV(vsum2sws, 4, 26); +GEN_VXFORM_ENV(vsumsws, 4, 30); +GEN_VXFORM_ENV(vaddfp, 5, 0); +GEN_VXFORM_ENV(vsubfp, 5, 1); +GEN_VXFORM_ENV(vmaxfp, 5, 16); +GEN_VXFORM_ENV(vminfp, 5, 17); + +#define GEN_VXRFORM1(opname, name, str, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr ra, rb, rd; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + ra = gen_avr_ptr(rA(ctx->opcode)); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##opname(cpu_env, rd, ra, rb); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + +#define GEN_VXRFORM(name, opc2, opc3) \ + GEN_VXRFORM1(name, name, #name, opc2, opc3) \ + GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4))) + +/* + * Support for Altivec instructions that use bit 31 (Rc) as an opcode + * bit but also use bit 21 as an actual Rc bit. In general, thse pairs + * come from different versions of the ISA, so we must also support a + * pair of flags for each instruction. + */ +#define GEN_VXRFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1) \ +static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ +{ \ + if ((Rc(ctx->opcode) == 0) && \ + ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \ + if (Rc21(ctx->opcode) == 0) { \ + gen_##name0(ctx); \ + } else { \ + gen_##name0##_(ctx); \ + } \ + } else if ((Rc(ctx->opcode) == 1) && \ + ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \ + if (Rc21(ctx->opcode) == 0) { \ + gen_##name1(ctx); \ + } else { \ + gen_##name1##_(ctx); \ + } \ + } else { \ + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ + } \ +} + +GEN_VXRFORM(vcmpequb, 3, 0) +GEN_VXRFORM(vcmpequh, 3, 1) +GEN_VXRFORM(vcmpequw, 3, 2) +GEN_VXRFORM(vcmpequd, 3, 3) +GEN_VXRFORM(vcmpgtsb, 3, 12) +GEN_VXRFORM(vcmpgtsh, 3, 13) +GEN_VXRFORM(vcmpgtsw, 3, 14) +GEN_VXRFORM(vcmpgtsd, 3, 15) +GEN_VXRFORM(vcmpgtub, 3, 8) +GEN_VXRFORM(vcmpgtuh, 3, 9) +GEN_VXRFORM(vcmpgtuw, 3, 10) +GEN_VXRFORM(vcmpgtud, 3, 11) +GEN_VXRFORM(vcmpeqfp, 3, 3) +GEN_VXRFORM(vcmpgefp, 3, 7) +GEN_VXRFORM(vcmpgtfp, 3, 11) +GEN_VXRFORM(vcmpbfp, 3, 15) + +GEN_VXRFORM_DUAL(vcmpeqfp, PPC_ALTIVEC, PPC_NONE, \ + vcmpequd, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \ + vcmpgtsd, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXRFORM_DUAL(vcmpgtfp, PPC_ALTIVEC, PPC_NONE, \ + vcmpgtud, PPC_NONE, PPC2_ALTIVEC_207) + +#define GEN_VXFORM_SIMM(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rd; \ + TCGv_i32 simm; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + simm = tcg_const_i32(SIMM5(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name (rd, simm); \ + tcg_temp_free_i32(simm); \ + tcg_temp_free_ptr(rd); \ + } + +GEN_VXFORM_SIMM(vspltisb, 6, 12); +GEN_VXFORM_SIMM(vspltish, 6, 13); +GEN_VXFORM_SIMM(vspltisw, 6, 14); + +#define GEN_VXFORM_NOA(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb, rd; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name (rd, rb); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + +#define GEN_VXFORM_NOA_ENV(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb, rd; \ + \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name(cpu_env, rd, rb); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + +GEN_VXFORM_NOA(vupkhsb, 7, 8); +GEN_VXFORM_NOA(vupkhsh, 7, 9); +GEN_VXFORM_NOA(vupkhsw, 7, 25); +GEN_VXFORM_NOA(vupklsb, 7, 10); +GEN_VXFORM_NOA(vupklsh, 7, 11); +GEN_VXFORM_NOA(vupklsw, 7, 27); +GEN_VXFORM_NOA(vupkhpx, 7, 13); +GEN_VXFORM_NOA(vupklpx, 7, 15); +GEN_VXFORM_NOA_ENV(vrefp, 5, 4); +GEN_VXFORM_NOA_ENV(vrsqrtefp, 5, 5); +GEN_VXFORM_NOA_ENV(vexptefp, 5, 6); +GEN_VXFORM_NOA_ENV(vlogefp, 5, 7); +GEN_VXFORM_NOA_ENV(vrfim, 5, 11); +GEN_VXFORM_NOA_ENV(vrfin, 5, 8); +GEN_VXFORM_NOA_ENV(vrfip, 5, 10); +GEN_VXFORM_NOA_ENV(vrfiz, 5, 9); + +#define GEN_VXFORM_SIMM(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rd; \ + TCGv_i32 simm; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + simm = tcg_const_i32(SIMM5(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name (rd, simm); \ + tcg_temp_free_i32(simm); \ + tcg_temp_free_ptr(rd); \ + } + +#define GEN_VXFORM_UIMM(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb, rd; \ + TCGv_i32 uimm; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + uimm = tcg_const_i32(UIMM5(ctx->opcode)); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name (rd, rb, uimm); \ + tcg_temp_free_i32(uimm); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + +#define GEN_VXFORM_UIMM_ENV(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb, rd; \ + TCGv_i32 uimm; \ + \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + uimm = tcg_const_i32(UIMM5(ctx->opcode)); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name(cpu_env, rd, rb, uimm); \ + tcg_temp_free_i32(uimm); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + +GEN_VXFORM_UIMM(vspltb, 6, 8); +GEN_VXFORM_UIMM(vsplth, 6, 9); +GEN_VXFORM_UIMM(vspltw, 6, 10); +GEN_VXFORM_UIMM_ENV(vcfux, 5, 12); +GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13); +GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14); +GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15); + +static void gen_vsldoi(DisasContext *ctx) +{ + TCGv_ptr ra, rb, rd; + TCGv_i32 sh; + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + ra = gen_avr_ptr(rA(ctx->opcode)); + rb = gen_avr_ptr(rB(ctx->opcode)); + rd = gen_avr_ptr(rD(ctx->opcode)); + sh = tcg_const_i32(VSH(ctx->opcode)); + gen_helper_vsldoi (rd, ra, rb, sh); + tcg_temp_free_ptr(ra); + tcg_temp_free_ptr(rb); + tcg_temp_free_ptr(rd); + tcg_temp_free_i32(sh); +} + +#define GEN_VAFORM_PAIRED(name0, name1, opc2) \ +static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ + { \ + TCGv_ptr ra, rb, rc, rd; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + ra = gen_avr_ptr(rA(ctx->opcode)); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rc = gen_avr_ptr(rC(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + if (Rc(ctx->opcode)) { \ + gen_helper_##name1(cpu_env, rd, ra, rb, rc); \ + } else { \ + gen_helper_##name0(cpu_env, rd, ra, rb, rc); \ + } \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rc); \ + tcg_temp_free_ptr(rd); \ + } + +GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16) + +static void gen_vmladduhm(DisasContext *ctx) +{ + TCGv_ptr ra, rb, rc, rd; + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + ra = gen_avr_ptr(rA(ctx->opcode)); + rb = gen_avr_ptr(rB(ctx->opcode)); + rc = gen_avr_ptr(rC(ctx->opcode)); + rd = gen_avr_ptr(rD(ctx->opcode)); + gen_helper_vmladduhm(rd, ra, rb, rc); + tcg_temp_free_ptr(ra); + tcg_temp_free_ptr(rb); + tcg_temp_free_ptr(rc); + tcg_temp_free_ptr(rd); +} + +GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18) +GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19) +GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20) +GEN_VAFORM_PAIRED(vsel, vperm, 21) +GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) + +GEN_VXFORM_NOA(vclzb, 1, 28) +GEN_VXFORM_NOA(vclzh, 1, 29) +GEN_VXFORM_NOA(vclzw, 1, 30) +GEN_VXFORM_NOA(vclzd, 1, 31) +GEN_VXFORM_NOA(vpopcntb, 1, 28) +GEN_VXFORM_NOA(vpopcnth, 1, 29) +GEN_VXFORM_NOA(vpopcntw, 1, 30) +GEN_VXFORM_NOA(vpopcntd, 1, 31) +GEN_VXFORM_DUAL(vclzb, PPC_NONE, PPC2_ALTIVEC_207, \ + vpopcntb, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM_DUAL(vclzh, PPC_NONE, PPC2_ALTIVEC_207, \ + vpopcnth, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM_DUAL(vclzw, PPC_NONE, PPC2_ALTIVEC_207, \ + vpopcntw, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM_DUAL(vclzd, PPC_NONE, PPC2_ALTIVEC_207, \ + vpopcntd, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM(vbpermq, 6, 21); +GEN_VXFORM_NOA(vgbbd, 6, 20); +GEN_VXFORM(vpmsumb, 4, 16) +GEN_VXFORM(vpmsumh, 4, 17) +GEN_VXFORM(vpmsumw, 4, 18) +GEN_VXFORM(vpmsumd, 4, 19) + +#define GEN_BCD(op) \ +static void gen_##op(DisasContext *ctx) \ +{ \ + TCGv_ptr ra, rb, rd; \ + TCGv_i32 ps; \ + \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + \ + ra = gen_avr_ptr(rA(ctx->opcode)); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + \ + ps = tcg_const_i32((ctx->opcode & 0x200) != 0); \ + \ + gen_helper_##op(cpu_crf[6], rd, ra, rb, ps); \ + \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + tcg_temp_free_i32(ps); \ +} + +GEN_BCD(bcdadd) +GEN_BCD(bcdsub) + +GEN_VXFORM_DUAL(vsububm, PPC_ALTIVEC, PPC_NONE, \ + bcdadd, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM_DUAL(vsububs, PPC_ALTIVEC, PPC_NONE, \ + bcdadd, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM_DUAL(vsubuhm, PPC_ALTIVEC, PPC_NONE, \ + bcdsub, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM_DUAL(vsubuhs, PPC_ALTIVEC, PPC_NONE, \ + bcdsub, PPC_NONE, PPC2_ALTIVEC_207) + +static void gen_vsbox(DisasContext *ctx) +{ + TCGv_ptr ra, rd; + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + ra = gen_avr_ptr(rA(ctx->opcode)); + rd = gen_avr_ptr(rD(ctx->opcode)); + gen_helper_vsbox(rd, ra); + tcg_temp_free_ptr(ra); + tcg_temp_free_ptr(rd); +} + +GEN_VXFORM(vcipher, 4, 20) +GEN_VXFORM(vcipherlast, 4, 20) +GEN_VXFORM(vncipher, 4, 21) +GEN_VXFORM(vncipherlast, 4, 21) + +GEN_VXFORM_DUAL(vcipher, PPC_NONE, PPC2_ALTIVEC_207, + vcipherlast, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM_DUAL(vncipher, PPC_NONE, PPC2_ALTIVEC_207, + vncipherlast, PPC_NONE, PPC2_ALTIVEC_207) + +#define VSHASIGMA(op) \ +static void gen_##op(DisasContext *ctx) \ +{ \ + TCGv_ptr ra, rd; \ + TCGv_i32 st_six; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + ra = gen_avr_ptr(rA(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + st_six = tcg_const_i32(rB(ctx->opcode)); \ + gen_helper_##op(rd, ra, st_six); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rd); \ + tcg_temp_free_i32(st_six); \ +} + +VSHASIGMA(vshasigmaw) +VSHASIGMA(vshasigmad) + +GEN_VXFORM3(vpermxor, 22, 0xFF) +GEN_VXFORM_DUAL(vsldoi, PPC_ALTIVEC, PPC_NONE, + vpermxor, PPC_NONE, PPC2_ALTIVEC_207) + +#undef GEN_VR_LDX +#undef GEN_VR_STX +#undef GEN_VR_LVE +#undef GEN_VR_STVE + +#undef GEN_VX_LOGICAL +#undef GEN_VX_LOGICAL_207 +#undef GEN_VXFORM +#undef GEN_VXFORM_207 +#undef GEN_VXFORM_DUAL +#undef GEN_VXRFORM_DUAL +#undef GEN_VXRFORM1 +#undef GEN_VXRFORM +#undef GEN_VXFORM_SIMM +#undef GEN_VXFORM_NOA +#undef GEN_VXFORM_UIMM +#undef GEN_VAFORM_PAIRED diff --git a/target-ppc/translate/vmx-ops.c b/target-ppc/translate/vmx-ops.c new file mode 100644 index 0000000000..185dc71fb9 --- /dev/null +++ b/target-ppc/translate/vmx-ops.c @@ -0,0 +1,245 @@ +#define GEN_VR_LDX(name, opc2, opc3) \ +GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) +#define GEN_VR_STX(name, opc2, opc3) \ +GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) +#define GEN_VR_LVE(name, opc2, opc3) \ + GEN_HANDLER(lve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) +#define GEN_VR_STVE(name, opc2, opc3) \ + GEN_HANDLER(stve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) +GEN_VR_LDX(lvx, 0x07, 0x03), +GEN_VR_LDX(lvxl, 0x07, 0x0B), +GEN_VR_LVE(bx, 0x07, 0x00), +GEN_VR_LVE(hx, 0x07, 0x01), +GEN_VR_LVE(wx, 0x07, 0x02), +GEN_VR_STX(svx, 0x07, 0x07), +GEN_VR_STX(svxl, 0x07, 0x0F), +GEN_VR_STVE(bx, 0x07, 0x04), +GEN_VR_STVE(hx, 0x07, 0x05), +GEN_VR_STVE(wx, 0x07, 0x06), + +#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3) \ +GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) + +#define GEN_VX_LOGICAL_207(name, tcg_op, opc2, opc3) \ +GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207) + +GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16), +GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17), +GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18), +GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19), +GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20), +GEN_VX_LOGICAL_207(veqv, tcg_gen_eqv_i64, 2, 26), +GEN_VX_LOGICAL_207(vnand, tcg_gen_nand_i64, 2, 22), +GEN_VX_LOGICAL_207(vorc, tcg_gen_orc_i64, 2, 21), + +#define GEN_VXFORM(name, opc2, opc3) \ +GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) + +#define GEN_VXFORM_207(name, opc2, opc3) \ +GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207) + +#define GEN_VXFORM_DUAL(name0, name1, opc2, opc3, type0, type1) \ +GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, type0, type1) + +#define GEN_VXRFORM_DUAL(name0, name1, opc2, opc3, tp0, tp1) \ +GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, tp0, tp1), \ +GEN_HANDLER_E(name0##_##name1, 0x4, opc2, (opc3 | 0x10), 0x00000000, tp0, tp1), + +GEN_VXFORM(vaddubm, 0, 0), +GEN_VXFORM(vadduhm, 0, 1), +GEN_VXFORM(vadduwm, 0, 2), +GEN_VXFORM_207(vaddudm, 0, 3), +GEN_VXFORM_DUAL(vsububm, bcdadd, 0, 16, PPC_ALTIVEC, PPC_NONE), +GEN_VXFORM_DUAL(vsubuhm, bcdsub, 0, 17, PPC_ALTIVEC, PPC_NONE), +GEN_VXFORM(vsubuwm, 0, 18), +GEN_VXFORM_207(vsubudm, 0, 19), +GEN_VXFORM(vmaxub, 1, 0), +GEN_VXFORM(vmaxuh, 1, 1), +GEN_VXFORM(vmaxuw, 1, 2), +GEN_VXFORM_207(vmaxud, 1, 3), +GEN_VXFORM(vmaxsb, 1, 4), +GEN_VXFORM(vmaxsh, 1, 5), +GEN_VXFORM(vmaxsw, 1, 6), +GEN_VXFORM_207(vmaxsd, 1, 7), +GEN_VXFORM(vminub, 1, 8), +GEN_VXFORM(vminuh, 1, 9), +GEN_VXFORM(vminuw, 1, 10), +GEN_VXFORM_207(vminud, 1, 11), +GEN_VXFORM(vminsb, 1, 12), +GEN_VXFORM(vminsh, 1, 13), +GEN_VXFORM(vminsw, 1, 14), +GEN_VXFORM_207(vminsd, 1, 15), +GEN_VXFORM(vavgub, 1, 16), +GEN_VXFORM(vavguh, 1, 17), +GEN_VXFORM(vavguw, 1, 18), +GEN_VXFORM(vavgsb, 1, 20), +GEN_VXFORM(vavgsh, 1, 21), +GEN_VXFORM(vavgsw, 1, 22), +GEN_VXFORM(vmrghb, 6, 0), +GEN_VXFORM(vmrghh, 6, 1), +GEN_VXFORM(vmrghw, 6, 2), +GEN_VXFORM(vmrglb, 6, 4), +GEN_VXFORM(vmrglh, 6, 5), +GEN_VXFORM(vmrglw, 6, 6), +GEN_VXFORM_207(vmrgew, 6, 30), +GEN_VXFORM_207(vmrgow, 6, 26), +GEN_VXFORM(vmuloub, 4, 0), +GEN_VXFORM(vmulouh, 4, 1), +GEN_VXFORM_DUAL(vmulouw, vmuluwm, 4, 2, PPC_ALTIVEC, PPC_NONE), +GEN_VXFORM(vmulosb, 4, 4), +GEN_VXFORM(vmulosh, 4, 5), +GEN_VXFORM_207(vmulosw, 4, 6), +GEN_VXFORM(vmuleub, 4, 8), +GEN_VXFORM(vmuleuh, 4, 9), +GEN_VXFORM_207(vmuleuw, 4, 10), +GEN_VXFORM(vmulesb, 4, 12), +GEN_VXFORM(vmulesh, 4, 13), +GEN_VXFORM_207(vmulesw, 4, 14), +GEN_VXFORM(vslb, 2, 4), +GEN_VXFORM(vslh, 2, 5), +GEN_VXFORM(vslw, 2, 6), +GEN_VXFORM_207(vsld, 2, 23), +GEN_VXFORM(vsrb, 2, 8), +GEN_VXFORM(vsrh, 2, 9), +GEN_VXFORM(vsrw, 2, 10), +GEN_VXFORM_207(vsrd, 2, 27), +GEN_VXFORM(vsrab, 2, 12), +GEN_VXFORM(vsrah, 2, 13), +GEN_VXFORM(vsraw, 2, 14), +GEN_VXFORM_207(vsrad, 2, 15), +GEN_VXFORM(vslo, 6, 16), +GEN_VXFORM(vsro, 6, 17), +GEN_VXFORM(vaddcuw, 0, 6), +GEN_VXFORM(vsubcuw, 0, 22), +GEN_VXFORM(vaddubs, 0, 8), +GEN_VXFORM(vadduhs, 0, 9), +GEN_VXFORM(vadduws, 0, 10), +GEN_VXFORM(vaddsbs, 0, 12), +GEN_VXFORM(vaddshs, 0, 13), +GEN_VXFORM(vaddsws, 0, 14), +GEN_VXFORM_DUAL(vsububs, bcdadd, 0, 24, PPC_ALTIVEC, PPC_NONE), +GEN_VXFORM_DUAL(vsubuhs, bcdsub, 0, 25, PPC_ALTIVEC, PPC_NONE), +GEN_VXFORM(vsubuws, 0, 26), +GEN_VXFORM(vsubsbs, 0, 28), +GEN_VXFORM(vsubshs, 0, 29), +GEN_VXFORM(vsubsws, 0, 30), +GEN_VXFORM_207(vadduqm, 0, 4), +GEN_VXFORM_207(vaddcuq, 0, 5), +GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207), +GEN_VXFORM_207(vsubuqm, 0, 20), +GEN_VXFORM_207(vsubcuq, 0, 21), +GEN_VXFORM_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207), +GEN_VXFORM(vrlb, 2, 0), +GEN_VXFORM(vrlh, 2, 1), +GEN_VXFORM(vrlw, 2, 2), +GEN_VXFORM_207(vrld, 2, 3), +GEN_VXFORM(vsl, 2, 7), +GEN_VXFORM(vsr, 2, 11), +GEN_VXFORM(vpkuhum, 7, 0), +GEN_VXFORM(vpkuwum, 7, 1), +GEN_VXFORM_207(vpkudum, 7, 17), +GEN_VXFORM(vpkuhus, 7, 2), +GEN_VXFORM(vpkuwus, 7, 3), +GEN_VXFORM_207(vpkudus, 7, 19), +GEN_VXFORM(vpkshus, 7, 4), +GEN_VXFORM(vpkswus, 7, 5), +GEN_VXFORM_207(vpksdus, 7, 21), +GEN_VXFORM(vpkshss, 7, 6), +GEN_VXFORM(vpkswss, 7, 7), +GEN_VXFORM_207(vpksdss, 7, 23), +GEN_VXFORM(vpkpx, 7, 12), +GEN_VXFORM(vsum4ubs, 4, 24), +GEN_VXFORM(vsum4sbs, 4, 28), +GEN_VXFORM(vsum4shs, 4, 25), +GEN_VXFORM(vsum2sws, 4, 26), +GEN_VXFORM(vsumsws, 4, 30), +GEN_VXFORM(vaddfp, 5, 0), +GEN_VXFORM(vsubfp, 5, 1), +GEN_VXFORM(vmaxfp, 5, 16), +GEN_VXFORM(vminfp, 5, 17), + +#define GEN_VXRFORM1(opname, name, str, opc2, opc3) \ + GEN_HANDLER2(name, str, 0x4, opc2, opc3, 0x00000000, PPC_ALTIVEC), +#define GEN_VXRFORM(name, opc2, opc3) \ + GEN_VXRFORM1(name, name, #name, opc2, opc3) \ + GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4))) +GEN_VXRFORM(vcmpequb, 3, 0) +GEN_VXRFORM(vcmpequh, 3, 1) +GEN_VXRFORM(vcmpequw, 3, 2) +GEN_VXRFORM(vcmpgtsb, 3, 12) +GEN_VXRFORM(vcmpgtsh, 3, 13) +GEN_VXRFORM(vcmpgtsw, 3, 14) +GEN_VXRFORM(vcmpgtub, 3, 8) +GEN_VXRFORM(vcmpgtuh, 3, 9) +GEN_VXRFORM(vcmpgtuw, 3, 10) +GEN_VXRFORM_DUAL(vcmpeqfp, vcmpequd, 3, 3, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM(vcmpgefp, 3, 7) +GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE) + +#define GEN_VXFORM_SIMM(name, opc2, opc3) \ + GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) +GEN_VXFORM_SIMM(vspltisb, 6, 12), +GEN_VXFORM_SIMM(vspltish, 6, 13), +GEN_VXFORM_SIMM(vspltisw, 6, 14), + +#define GEN_VXFORM_NOA(name, opc2, opc3) \ + GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC) +GEN_VXFORM_NOA(vupkhsb, 7, 8), +GEN_VXFORM_NOA(vupkhsh, 7, 9), +GEN_VXFORM_207(vupkhsw, 7, 25), +GEN_VXFORM_NOA(vupklsb, 7, 10), +GEN_VXFORM_NOA(vupklsh, 7, 11), +GEN_VXFORM_207(vupklsw, 7, 27), +GEN_VXFORM_NOA(vupkhpx, 7, 13), +GEN_VXFORM_NOA(vupklpx, 7, 15), +GEN_VXFORM_NOA(vrefp, 5, 4), +GEN_VXFORM_NOA(vrsqrtefp, 5, 5), +GEN_VXFORM_NOA(vexptefp, 5, 6), +GEN_VXFORM_NOA(vlogefp, 5, 7), +GEN_VXFORM_NOA(vrfim, 5, 11), +GEN_VXFORM_NOA(vrfin, 5, 8), +GEN_VXFORM_NOA(vrfip, 5, 10), +GEN_VXFORM_NOA(vrfiz, 5, 9), + +#define GEN_VXFORM_UIMM(name, opc2, opc3) \ + GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) +GEN_VXFORM_UIMM(vspltb, 6, 8), +GEN_VXFORM_UIMM(vsplth, 6, 9), +GEN_VXFORM_UIMM(vspltw, 6, 10), +GEN_VXFORM_UIMM(vcfux, 5, 12), +GEN_VXFORM_UIMM(vcfsx, 5, 13), +GEN_VXFORM_UIMM(vctuxs, 5, 14), +GEN_VXFORM_UIMM(vctsxs, 5, 15), + + +#define GEN_VAFORM_PAIRED(name0, name1, opc2) \ + GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC) +GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16), +GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18), +GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19), +GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20), +GEN_VAFORM_PAIRED(vsel, vperm, 21), +GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), + +GEN_VXFORM_DUAL(vclzb, vpopcntb, 1, 28, PPC_NONE, PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL(vclzh, vpopcnth, 1, 29, PPC_NONE, PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL(vclzw, vpopcntw, 1, 30, PPC_NONE, PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL(vclzd, vpopcntd, 1, 31, PPC_NONE, PPC2_ALTIVEC_207), + +GEN_VXFORM_207(vbpermq, 6, 21), +GEN_VXFORM_207(vgbbd, 6, 20), +GEN_VXFORM_207(vpmsumb, 4, 16), +GEN_VXFORM_207(vpmsumh, 4, 17), +GEN_VXFORM_207(vpmsumw, 4, 18), +GEN_VXFORM_207(vpmsumd, 4, 19), + +GEN_VXFORM_207(vsbox, 4, 23), + +GEN_VXFORM_DUAL(vcipher, vcipherlast, 4, 20, PPC_NONE, PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL(vncipher, vncipherlast, 4, 21, PPC_NONE, PPC2_ALTIVEC_207), + +GEN_VXFORM_207(vshasigmaw, 1, 26), +GEN_VXFORM_207(vshasigmad, 1, 27), + +GEN_VXFORM_DUAL(vsldoi, vpermxor, 22, 0xFF, PPC_ALTIVEC, PPC_NONE), From 3014427af550dfda54a067b15f7c69bcc23cec05 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:24 +1000 Subject: [PATCH 21/64] ppc: Move VSX ops out of translate.c Makes things a bit more manageable Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate.c | 994 +------------------------------- target-ppc/translate/vsx-impl.c | 721 +++++++++++++++++++++++ target-ppc/translate/vsx-ops.c | 270 +++++++++ 3 files changed, 994 insertions(+), 991 deletions(-) create mode 100644 target-ppc/translate/vsx-impl.c create mode 100644 target-ppc/translate/vsx-ops.c diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 210152a68c..a327072e06 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -5243,6 +5243,8 @@ static void gen_rfsvc(DisasContext *ctx) #include "translate/vmx-impl.c" +#include "translate/vsx-impl.c" + /* svc is not implemented for now */ /* BookE specific instructions */ @@ -6042,721 +6044,6 @@ static void gen_maddhd_maddhdu(DisasContext *ctx) } #endif /* defined(TARGET_PPC64) */ -/*** VSX extension ***/ - -static inline TCGv_i64 cpu_vsrh(int n) -{ - if (n < 32) { - return cpu_fpr[n]; - } else { - return cpu_avrh[n-32]; - } -} - -static inline TCGv_i64 cpu_vsrl(int n) -{ - if (n < 32) { - return cpu_vsr[n]; - } else { - return cpu_avrl[n-32]; - } -} - -#define VSX_LOAD_SCALAR(name, operation) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - gen_qemu_##operation(ctx, cpu_vsrh(xT(ctx->opcode)), EA); \ - /* NOTE: cpu_vsrl is undefined */ \ - tcg_temp_free(EA); \ -} - -VSX_LOAD_SCALAR(lxsdx, ld64) -VSX_LOAD_SCALAR(lxsiwax, ld32s_i64) -VSX_LOAD_SCALAR(lxsiwzx, ld32u_i64) -VSX_LOAD_SCALAR(lxsspx, ld32fs) - -static void gen_lxvd2x(DisasContext *ctx) -{ - TCGv EA; - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - gen_set_access_type(ctx, ACCESS_INT); - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); - tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_vsrl(xT(ctx->opcode)), EA); - tcg_temp_free(EA); -} - -static void gen_lxvdsx(DisasContext *ctx) -{ - TCGv EA; - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - gen_set_access_type(ctx, ACCESS_INT); - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode))); - tcg_temp_free(EA); -} - -static void gen_lxvw4x(DisasContext *ctx) -{ - TCGv EA; - TCGv_i64 tmp; - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - gen_set_access_type(ctx, ACCESS_INT); - EA = tcg_temp_new(); - tmp = tcg_temp_new_i64(); - - gen_addr_reg_index(ctx, EA); - gen_qemu_ld32u_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, xth, EA); - tcg_gen_deposit_i64(xth, xth, tmp, 32, 32); - - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, xtl, EA); - tcg_gen_deposit_i64(xtl, xtl, tmp, 32, 32); - - tcg_temp_free(EA); - tcg_temp_free_i64(tmp); -} - -#define VSX_STORE_SCALAR(name, operation) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - gen_qemu_##operation(ctx, cpu_vsrh(xS(ctx->opcode)), EA); \ - tcg_temp_free(EA); \ -} - -VSX_STORE_SCALAR(stxsdx, st64) -VSX_STORE_SCALAR(stxsiwx, st32_i64) -VSX_STORE_SCALAR(stxsspx, st32fs) - -static void gen_stxvd2x(DisasContext *ctx) -{ - TCGv EA; - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - gen_set_access_type(ctx, ACCESS_INT); - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - gen_qemu_st64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); - tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); - tcg_temp_free(EA); -} - -static void gen_stxvw4x(DisasContext *ctx) -{ - TCGv_i64 tmp; - TCGv EA; - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - gen_set_access_type(ctx, ACCESS_INT); - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - tmp = tcg_temp_new_i64(); - - tcg_gen_shri_i64(tmp, cpu_vsrh(xS(ctx->opcode)), 32); - gen_qemu_st32_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); - - tcg_gen_shri_i64(tmp, cpu_vsrl(xS(ctx->opcode)), 32); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); - - tcg_temp_free(EA); - tcg_temp_free_i64(tmp); -} - -#define MV_VSRW(name, tcgop1, tcgop2, target, source) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - if (xS(ctx->opcode) < 32) { \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - } else { \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - } \ - TCGv_i64 tmp = tcg_temp_new_i64(); \ - tcg_gen_##tcgop1(tmp, source); \ - tcg_gen_##tcgop2(target, tmp); \ - tcg_temp_free_i64(tmp); \ -} - - -MV_VSRW(mfvsrwz, ext32u_i64, trunc_i64_tl, cpu_gpr[rA(ctx->opcode)], \ - cpu_vsrh(xS(ctx->opcode))) -MV_VSRW(mtvsrwa, extu_tl_i64, ext32s_i64, cpu_vsrh(xT(ctx->opcode)), \ - cpu_gpr[rA(ctx->opcode)]) -MV_VSRW(mtvsrwz, extu_tl_i64, ext32u_i64, cpu_vsrh(xT(ctx->opcode)), \ - cpu_gpr[rA(ctx->opcode)]) - -#if defined(TARGET_PPC64) -#define MV_VSRD(name, target, source) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - if (xS(ctx->opcode) < 32) { \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - } else { \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - } \ - tcg_gen_mov_i64(target, source); \ -} - -MV_VSRD(mfvsrd, cpu_gpr[rA(ctx->opcode)], cpu_vsrh(xS(ctx->opcode))) -MV_VSRD(mtvsrd, cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)]) - -#endif - -static void gen_xxpermdi(DisasContext *ctx) -{ - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - - if (unlikely((xT(ctx->opcode) == xA(ctx->opcode)) || - (xT(ctx->opcode) == xB(ctx->opcode)))) { - TCGv_i64 xh, xl; - - xh = tcg_temp_new_i64(); - xl = tcg_temp_new_i64(); - - if ((DM(ctx->opcode) & 2) == 0) { - tcg_gen_mov_i64(xh, cpu_vsrh(xA(ctx->opcode))); - } else { - tcg_gen_mov_i64(xh, cpu_vsrl(xA(ctx->opcode))); - } - if ((DM(ctx->opcode) & 1) == 0) { - tcg_gen_mov_i64(xl, cpu_vsrh(xB(ctx->opcode))); - } else { - tcg_gen_mov_i64(xl, cpu_vsrl(xB(ctx->opcode))); - } - - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xh); - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xl); - - tcg_temp_free_i64(xh); - tcg_temp_free_i64(xl); - } else { - if ((DM(ctx->opcode) & 2) == 0) { - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode))); - } else { - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode))); - } - if ((DM(ctx->opcode) & 1) == 0) { - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xB(ctx->opcode))); - } else { - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xB(ctx->opcode))); - } - } -} - -#define OP_ABS 1 -#define OP_NABS 2 -#define OP_NEG 3 -#define OP_CPSGN 4 -#define SGN_MASK_DP 0x8000000000000000ull -#define SGN_MASK_SP 0x8000000080000000ull - -#define VSX_SCALAR_MOVE(name, op, sgn_mask) \ -static void glue(gen_, name)(DisasContext * ctx) \ - { \ - TCGv_i64 xb, sgm; \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - xb = tcg_temp_new_i64(); \ - sgm = tcg_temp_new_i64(); \ - tcg_gen_mov_i64(xb, cpu_vsrh(xB(ctx->opcode))); \ - tcg_gen_movi_i64(sgm, sgn_mask); \ - switch (op) { \ - case OP_ABS: { \ - tcg_gen_andc_i64(xb, xb, sgm); \ - break; \ - } \ - case OP_NABS: { \ - tcg_gen_or_i64(xb, xb, sgm); \ - break; \ - } \ - case OP_NEG: { \ - tcg_gen_xor_i64(xb, xb, sgm); \ - break; \ - } \ - case OP_CPSGN: { \ - TCGv_i64 xa = tcg_temp_new_i64(); \ - tcg_gen_mov_i64(xa, cpu_vsrh(xA(ctx->opcode))); \ - tcg_gen_and_i64(xa, xa, sgm); \ - tcg_gen_andc_i64(xb, xb, sgm); \ - tcg_gen_or_i64(xb, xb, xa); \ - tcg_temp_free_i64(xa); \ - break; \ - } \ - } \ - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xb); \ - tcg_temp_free_i64(xb); \ - tcg_temp_free_i64(sgm); \ - } - -VSX_SCALAR_MOVE(xsabsdp, OP_ABS, SGN_MASK_DP) -VSX_SCALAR_MOVE(xsnabsdp, OP_NABS, SGN_MASK_DP) -VSX_SCALAR_MOVE(xsnegdp, OP_NEG, SGN_MASK_DP) -VSX_SCALAR_MOVE(xscpsgndp, OP_CPSGN, SGN_MASK_DP) - -#define VSX_VECTOR_MOVE(name, op, sgn_mask) \ -static void glue(gen_, name)(DisasContext * ctx) \ - { \ - TCGv_i64 xbh, xbl, sgm; \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - xbh = tcg_temp_new_i64(); \ - xbl = tcg_temp_new_i64(); \ - sgm = tcg_temp_new_i64(); \ - tcg_gen_mov_i64(xbh, cpu_vsrh(xB(ctx->opcode))); \ - tcg_gen_mov_i64(xbl, cpu_vsrl(xB(ctx->opcode))); \ - tcg_gen_movi_i64(sgm, sgn_mask); \ - switch (op) { \ - case OP_ABS: { \ - tcg_gen_andc_i64(xbh, xbh, sgm); \ - tcg_gen_andc_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_NABS: { \ - tcg_gen_or_i64(xbh, xbh, sgm); \ - tcg_gen_or_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_NEG: { \ - tcg_gen_xor_i64(xbh, xbh, sgm); \ - tcg_gen_xor_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_CPSGN: { \ - TCGv_i64 xah = tcg_temp_new_i64(); \ - TCGv_i64 xal = tcg_temp_new_i64(); \ - tcg_gen_mov_i64(xah, cpu_vsrh(xA(ctx->opcode))); \ - tcg_gen_mov_i64(xal, cpu_vsrl(xA(ctx->opcode))); \ - tcg_gen_and_i64(xah, xah, sgm); \ - tcg_gen_and_i64(xal, xal, sgm); \ - tcg_gen_andc_i64(xbh, xbh, sgm); \ - tcg_gen_andc_i64(xbl, xbl, sgm); \ - tcg_gen_or_i64(xbh, xbh, xah); \ - tcg_gen_or_i64(xbl, xbl, xal); \ - tcg_temp_free_i64(xah); \ - tcg_temp_free_i64(xal); \ - break; \ - } \ - } \ - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xbh); \ - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xbl); \ - tcg_temp_free_i64(xbh); \ - tcg_temp_free_i64(xbl); \ - tcg_temp_free_i64(sgm); \ - } - -VSX_VECTOR_MOVE(xvabsdp, OP_ABS, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvnabsdp, OP_NABS, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvnegdp, OP_NEG, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvcpsgndp, OP_CPSGN, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvabssp, OP_ABS, SGN_MASK_SP) -VSX_VECTOR_MOVE(xvnabssp, OP_NABS, SGN_MASK_SP) -VSX_VECTOR_MOVE(xvnegsp, OP_NEG, SGN_MASK_SP) -VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP) - -#define GEN_VSX_HELPER_2(name, op1, op2, inval, type) \ -static void gen_##name(DisasContext * ctx) \ -{ \ - TCGv_i32 opc; \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ - opc = tcg_const_i32(ctx->opcode); \ - gen_helper_##name(cpu_env, opc); \ - tcg_temp_free_i32(opc); \ -} - -#define GEN_VSX_HELPER_XT_XB_ENV(name, op1, op2, inval, type) \ -static void gen_##name(DisasContext * ctx) \ -{ \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - /* NIP cannot be restored if the exception comes */ \ - /* from a helper. */ \ - gen_update_nip(ctx, ctx->nip - 4); \ - \ - gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env, \ - cpu_vsrh(xB(ctx->opcode))); \ -} - -GEN_VSX_HELPER_2(xsadddp, 0x00, 0x04, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xssubdp, 0x00, 0x05, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsmuldp, 0x00, 0x06, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsdivdp, 0x00, 0x07, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsredp, 0x14, 0x05, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xssqrtdp, 0x16, 0x04, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsrsqrtedp, 0x14, 0x04, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xstdivdp, 0x14, 0x07, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xstsqrtdp, 0x14, 0x06, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsmaddadp, 0x04, 0x04, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsmaddmdp, 0x04, 0x05, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsmsubadp, 0x04, 0x06, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsmsubmdp, 0x04, 0x07, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsnmaddadp, 0x04, 0x14, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsnmaddmdp, 0x04, 0x15, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsnmsubadp, 0x04, 0x16, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsnmsubmdp, 0x04, 0x17, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xscmpodp, 0x0C, 0x05, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xscmpudp, 0x0C, 0x04, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsmindp, 0x00, 0x15, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX) -GEN_VSX_HELPER_XT_XB_ENV(xscvdpspn, 0x16, 0x10, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX) -GEN_VSX_HELPER_XT_XB_ENV(xscvspdpn, 0x16, 0x14, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xscvdpsxds, 0x10, 0x15, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xscvdpsxws, 0x10, 0x05, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xscvdpuxds, 0x10, 0x14, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xscvdpuxws, 0x10, 0x04, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xscvsxddp, 0x10, 0x17, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xscvuxddp, 0x10, 0x16, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsrdpi, 0x12, 0x04, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsrdpic, 0x16, 0x06, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsrdpim, 0x12, 0x07, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsrdpip, 0x12, 0x06, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xsrdpiz, 0x12, 0x05, 0, PPC2_VSX) -GEN_VSX_HELPER_XT_XB_ENV(xsrsp, 0x12, 0x11, 0, PPC2_VSX207) - -GEN_VSX_HELPER_2(xsaddsp, 0x00, 0x00, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xssubsp, 0x00, 0x01, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsmulsp, 0x00, 0x02, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsdivsp, 0x00, 0x03, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsresp, 0x14, 0x01, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsmaddasp, 0x04, 0x00, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsmaddmsp, 0x04, 0x01, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsmsubasp, 0x04, 0x02, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsmsubmsp, 0x04, 0x03, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsnmaddasp, 0x04, 0x10, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsnmaddmsp, 0x04, 0x11, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsnmsubasp, 0x04, 0x12, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xsnmsubmsp, 0x04, 0x13, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207) -GEN_VSX_HELPER_2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207) - -GEN_VSX_HELPER_2(xvadddp, 0x00, 0x0C, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmuldp, 0x00, 0x0E, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvdivdp, 0x00, 0x0F, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvredp, 0x14, 0x0D, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvsqrtdp, 0x16, 0x0C, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrsqrtedp, 0x14, 0x0C, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvtdivdp, 0x14, 0x0F, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvtsqrtdp, 0x14, 0x0E, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmaddadp, 0x04, 0x0C, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmaddmdp, 0x04, 0x0D, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmsubadp, 0x04, 0x0E, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmsubmdp, 0x04, 0x0F, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvnmaddadp, 0x04, 0x1C, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvnmaddmdp, 0x04, 0x1D, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvnmsubadp, 0x04, 0x1E, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvnmsubmdp, 0x04, 0x1F, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmaxdp, 0x00, 0x1C, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmindp, 0x00, 0x1D, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcmpeqdp, 0x0C, 0x0C, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcmpgtdp, 0x0C, 0x0D, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcmpgedp, 0x0C, 0x0E, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvdpsp, 0x12, 0x18, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvdpsxds, 0x10, 0x1D, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvdpsxws, 0x10, 0x0D, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvdpuxds, 0x10, 0x1C, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvdpuxws, 0x10, 0x0C, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvsxddp, 0x10, 0x1F, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvuxddp, 0x10, 0x1E, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvsxwdp, 0x10, 0x0F, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvuxwdp, 0x10, 0x0E, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrdpi, 0x12, 0x0C, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrdpic, 0x16, 0x0E, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrdpim, 0x12, 0x0F, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrdpip, 0x12, 0x0E, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrdpiz, 0x12, 0x0D, 0, PPC2_VSX) - -GEN_VSX_HELPER_2(xvaddsp, 0x00, 0x08, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvsubsp, 0x00, 0x09, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmulsp, 0x00, 0x0A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvdivsp, 0x00, 0x0B, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvresp, 0x14, 0x09, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvsqrtsp, 0x16, 0x08, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrsqrtesp, 0x14, 0x08, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvtdivsp, 0x14, 0x0B, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvtsqrtsp, 0x14, 0x0A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmaddasp, 0x04, 0x08, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmaddmsp, 0x04, 0x09, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmsubasp, 0x04, 0x0A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmsubmsp, 0x04, 0x0B, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvnmaddasp, 0x04, 0x18, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvnmaddmsp, 0x04, 0x19, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvnmsubasp, 0x04, 0x1A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvnmsubmsp, 0x04, 0x1B, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvmaxsp, 0x00, 0x18, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvminsp, 0x00, 0x19, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcmpeqsp, 0x0C, 0x08, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcmpgtsp, 0x0C, 0x09, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcmpgesp, 0x0C, 0x0A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvspdp, 0x12, 0x1C, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvspsxds, 0x10, 0x19, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvspsxws, 0x10, 0x09, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvspuxds, 0x10, 0x18, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvspuxws, 0x10, 0x08, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvsxdsp, 0x10, 0x1B, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvuxdsp, 0x10, 0x1A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvsxwsp, 0x10, 0x0B, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvcvuxwsp, 0x10, 0x0A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrspi, 0x12, 0x08, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrspic, 0x16, 0x0A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrspim, 0x12, 0x0B, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrspip, 0x12, 0x0A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvrspiz, 0x12, 0x09, 0, PPC2_VSX) - -#define VSX_LOGICAL(name, tcg_op) \ -static void glue(gen_, name)(DisasContext * ctx) \ - { \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - tcg_op(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode)), \ - cpu_vsrh(xB(ctx->opcode))); \ - tcg_op(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode)), \ - cpu_vsrl(xB(ctx->opcode))); \ - } - -VSX_LOGICAL(xxland, tcg_gen_and_i64) -VSX_LOGICAL(xxlandc, tcg_gen_andc_i64) -VSX_LOGICAL(xxlor, tcg_gen_or_i64) -VSX_LOGICAL(xxlxor, tcg_gen_xor_i64) -VSX_LOGICAL(xxlnor, tcg_gen_nor_i64) -VSX_LOGICAL(xxleqv, tcg_gen_eqv_i64) -VSX_LOGICAL(xxlnand, tcg_gen_nand_i64) -VSX_LOGICAL(xxlorc, tcg_gen_orc_i64) - -#define VSX_XXMRG(name, high) \ -static void glue(gen_, name)(DisasContext * ctx) \ - { \ - TCGv_i64 a0, a1, b0, b1; \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - a0 = tcg_temp_new_i64(); \ - a1 = tcg_temp_new_i64(); \ - b0 = tcg_temp_new_i64(); \ - b1 = tcg_temp_new_i64(); \ - if (high) { \ - tcg_gen_mov_i64(a0, cpu_vsrh(xA(ctx->opcode))); \ - tcg_gen_mov_i64(a1, cpu_vsrh(xA(ctx->opcode))); \ - tcg_gen_mov_i64(b0, cpu_vsrh(xB(ctx->opcode))); \ - tcg_gen_mov_i64(b1, cpu_vsrh(xB(ctx->opcode))); \ - } else { \ - tcg_gen_mov_i64(a0, cpu_vsrl(xA(ctx->opcode))); \ - tcg_gen_mov_i64(a1, cpu_vsrl(xA(ctx->opcode))); \ - tcg_gen_mov_i64(b0, cpu_vsrl(xB(ctx->opcode))); \ - tcg_gen_mov_i64(b1, cpu_vsrl(xB(ctx->opcode))); \ - } \ - tcg_gen_shri_i64(a0, a0, 32); \ - tcg_gen_shri_i64(b0, b0, 32); \ - tcg_gen_deposit_i64(cpu_vsrh(xT(ctx->opcode)), \ - b0, a0, 32, 32); \ - tcg_gen_deposit_i64(cpu_vsrl(xT(ctx->opcode)), \ - b1, a1, 32, 32); \ - tcg_temp_free_i64(a0); \ - tcg_temp_free_i64(a1); \ - tcg_temp_free_i64(b0); \ - tcg_temp_free_i64(b1); \ - } - -VSX_XXMRG(xxmrghw, 1) -VSX_XXMRG(xxmrglw, 0) - -static void gen_xxsel(DisasContext * ctx) -{ - TCGv_i64 a, b, c; - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - a = tcg_temp_new_i64(); - b = tcg_temp_new_i64(); - c = tcg_temp_new_i64(); - - tcg_gen_mov_i64(a, cpu_vsrh(xA(ctx->opcode))); - tcg_gen_mov_i64(b, cpu_vsrh(xB(ctx->opcode))); - tcg_gen_mov_i64(c, cpu_vsrh(xC(ctx->opcode))); - - tcg_gen_and_i64(b, b, c); - tcg_gen_andc_i64(a, a, c); - tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), a, b); - - tcg_gen_mov_i64(a, cpu_vsrl(xA(ctx->opcode))); - tcg_gen_mov_i64(b, cpu_vsrl(xB(ctx->opcode))); - tcg_gen_mov_i64(c, cpu_vsrl(xC(ctx->opcode))); - - tcg_gen_and_i64(b, b, c); - tcg_gen_andc_i64(a, a, c); - tcg_gen_or_i64(cpu_vsrl(xT(ctx->opcode)), a, b); - - tcg_temp_free_i64(a); - tcg_temp_free_i64(b); - tcg_temp_free_i64(c); -} - -static void gen_xxspltw(DisasContext *ctx) -{ - TCGv_i64 b, b2; - TCGv_i64 vsr = (UIM(ctx->opcode) & 2) ? - cpu_vsrl(xB(ctx->opcode)) : - cpu_vsrh(xB(ctx->opcode)); - - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - - b = tcg_temp_new_i64(); - b2 = tcg_temp_new_i64(); - - if (UIM(ctx->opcode) & 1) { - tcg_gen_ext32u_i64(b, vsr); - } else { - tcg_gen_shri_i64(b, vsr, 32); - } - - tcg_gen_shli_i64(b2, b, 32); - tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), b, b2); - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode))); - - tcg_temp_free_i64(b); - tcg_temp_free_i64(b2); -} - -static void gen_xxsldwi(DisasContext *ctx) -{ - TCGv_i64 xth, xtl; - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - xth = tcg_temp_new_i64(); - xtl = tcg_temp_new_i64(); - - switch (SHW(ctx->opcode)) { - case 0: { - tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode))); - tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode))); - break; - } - case 1: { - TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode))); - tcg_gen_shli_i64(xth, xth, 32); - tcg_gen_mov_i64(t0, cpu_vsrl(xA(ctx->opcode))); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_or_i64(xth, xth, t0); - tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode))); - tcg_gen_shli_i64(xtl, xtl, 32); - tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode))); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_or_i64(xtl, xtl, t0); - tcg_temp_free_i64(t0); - break; - } - case 2: { - tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode))); - tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode))); - break; - } - case 3: { - TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode))); - tcg_gen_shli_i64(xth, xth, 32); - tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode))); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_or_i64(xth, xth, t0); - tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode))); - tcg_gen_shli_i64(xtl, xtl, 32); - tcg_gen_mov_i64(t0, cpu_vsrl(xB(ctx->opcode))); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_or_i64(xtl, xtl, t0); - tcg_temp_free_i64(t0); - break; - } - } - - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xth); - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xtl); - - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); -} - #include "translate/dfp-impl.c" #include "translate/spe-impl.c" @@ -7364,282 +6651,7 @@ GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C), #include "translate/vmx-ops.c" -GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX), -GEN_HANDLER_E(lxsiwax, 0x1F, 0x0C, 0x02, 0, PPC_NONE, PPC2_VSX207), -GEN_HANDLER_E(lxsiwzx, 0x1F, 0x0C, 0x00, 0, PPC_NONE, PPC2_VSX207), -GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207), -GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX), -GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX), -GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX), - -GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX), -GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207), -GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207), -GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX), -GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX), - -GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207), -GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207), -GEN_HANDLER_E(mtvsrwz, 0x1F, 0x13, 0x07, 0x0000F800, PPC_NONE, PPC2_VSX207), -#if defined(TARGET_PPC64) -GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207), -GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207), -#endif - -#undef GEN_XX2FORM -#define GEN_XX2FORM(name, opc2, opc3, fl2) \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2) - -#undef GEN_XX3FORM -#define GEN_XX3FORM(name, opc2, opc3, fl2) \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 0, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 0, PPC_NONE, fl2) - -#undef GEN_XX2IFORM -#define GEN_XX2IFORM(name, opc2, opc3, fl2) \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 1, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 1, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 1, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 1, PPC_NONE, fl2) - -#undef GEN_XX3_RC_FORM -#define GEN_XX3_RC_FORM(name, opc2, opc3, fl2) \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x00, 0, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x00, 0, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x00, 0, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x00, 0, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x10, 0, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x10, 0, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x10, 0, PPC_NONE, fl2), \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x10, 0, PPC_NONE, fl2) - -#undef GEN_XX3FORM_DM -#define GEN_XX3FORM_DM(name, opc2, opc3) \ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\ -GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x0C, 0, PPC_NONE, PPC2_VSX) - -GEN_XX2FORM(xsabsdp, 0x12, 0x15, PPC2_VSX), -GEN_XX2FORM(xsnabsdp, 0x12, 0x16, PPC2_VSX), -GEN_XX2FORM(xsnegdp, 0x12, 0x17, PPC2_VSX), -GEN_XX3FORM(xscpsgndp, 0x00, 0x16, PPC2_VSX), - -GEN_XX2FORM(xvabsdp, 0x12, 0x1D, PPC2_VSX), -GEN_XX2FORM(xvnabsdp, 0x12, 0x1E, PPC2_VSX), -GEN_XX2FORM(xvnegdp, 0x12, 0x1F, PPC2_VSX), -GEN_XX3FORM(xvcpsgndp, 0x00, 0x1E, PPC2_VSX), -GEN_XX2FORM(xvabssp, 0x12, 0x19, PPC2_VSX), -GEN_XX2FORM(xvnabssp, 0x12, 0x1A, PPC2_VSX), -GEN_XX2FORM(xvnegsp, 0x12, 0x1B, PPC2_VSX), -GEN_XX3FORM(xvcpsgnsp, 0x00, 0x1A, PPC2_VSX), - -GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX), -GEN_XX3FORM(xssubdp, 0x00, 0x05, PPC2_VSX), -GEN_XX3FORM(xsmuldp, 0x00, 0x06, PPC2_VSX), -GEN_XX3FORM(xsdivdp, 0x00, 0x07, PPC2_VSX), -GEN_XX2FORM(xsredp, 0x14, 0x05, PPC2_VSX), -GEN_XX2FORM(xssqrtdp, 0x16, 0x04, PPC2_VSX), -GEN_XX2FORM(xsrsqrtedp, 0x14, 0x04, PPC2_VSX), -GEN_XX3FORM(xstdivdp, 0x14, 0x07, PPC2_VSX), -GEN_XX2FORM(xstsqrtdp, 0x14, 0x06, PPC2_VSX), -GEN_XX3FORM(xsmaddadp, 0x04, 0x04, PPC2_VSX), -GEN_XX3FORM(xsmaddmdp, 0x04, 0x05, PPC2_VSX), -GEN_XX3FORM(xsmsubadp, 0x04, 0x06, PPC2_VSX), -GEN_XX3FORM(xsmsubmdp, 0x04, 0x07, PPC2_VSX), -GEN_XX3FORM(xsnmaddadp, 0x04, 0x14, PPC2_VSX), -GEN_XX3FORM(xsnmaddmdp, 0x04, 0x15, PPC2_VSX), -GEN_XX3FORM(xsnmsubadp, 0x04, 0x16, PPC2_VSX), -GEN_XX3FORM(xsnmsubmdp, 0x04, 0x17, PPC2_VSX), -GEN_XX2IFORM(xscmpodp, 0x0C, 0x05, PPC2_VSX), -GEN_XX2IFORM(xscmpudp, 0x0C, 0x04, PPC2_VSX), -GEN_XX3FORM(xsmaxdp, 0x00, 0x14, PPC2_VSX), -GEN_XX3FORM(xsmindp, 0x00, 0x15, PPC2_VSX), -GEN_XX2FORM(xscvdpsp, 0x12, 0x10, PPC2_VSX), -GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207), -GEN_XX2FORM(xscvspdp, 0x12, 0x14, PPC2_VSX), -GEN_XX2FORM(xscvspdpn, 0x16, 0x14, PPC2_VSX207), -GEN_XX2FORM(xscvdpsxds, 0x10, 0x15, PPC2_VSX), -GEN_XX2FORM(xscvdpsxws, 0x10, 0x05, PPC2_VSX), -GEN_XX2FORM(xscvdpuxds, 0x10, 0x14, PPC2_VSX), -GEN_XX2FORM(xscvdpuxws, 0x10, 0x04, PPC2_VSX), -GEN_XX2FORM(xscvsxddp, 0x10, 0x17, PPC2_VSX), -GEN_XX2FORM(xscvuxddp, 0x10, 0x16, PPC2_VSX), -GEN_XX2FORM(xsrdpi, 0x12, 0x04, PPC2_VSX), -GEN_XX2FORM(xsrdpic, 0x16, 0x06, PPC2_VSX), -GEN_XX2FORM(xsrdpim, 0x12, 0x07, PPC2_VSX), -GEN_XX2FORM(xsrdpip, 0x12, 0x06, PPC2_VSX), -GEN_XX2FORM(xsrdpiz, 0x12, 0x05, PPC2_VSX), - -GEN_XX3FORM(xsaddsp, 0x00, 0x00, PPC2_VSX207), -GEN_XX3FORM(xssubsp, 0x00, 0x01, PPC2_VSX207), -GEN_XX3FORM(xsmulsp, 0x00, 0x02, PPC2_VSX207), -GEN_XX3FORM(xsdivsp, 0x00, 0x03, PPC2_VSX207), -GEN_XX2FORM(xsresp, 0x14, 0x01, PPC2_VSX207), -GEN_XX2FORM(xsrsp, 0x12, 0x11, PPC2_VSX207), -GEN_XX2FORM(xssqrtsp, 0x16, 0x00, PPC2_VSX207), -GEN_XX2FORM(xsrsqrtesp, 0x14, 0x00, PPC2_VSX207), -GEN_XX3FORM(xsmaddasp, 0x04, 0x00, PPC2_VSX207), -GEN_XX3FORM(xsmaddmsp, 0x04, 0x01, PPC2_VSX207), -GEN_XX3FORM(xsmsubasp, 0x04, 0x02, PPC2_VSX207), -GEN_XX3FORM(xsmsubmsp, 0x04, 0x03, PPC2_VSX207), -GEN_XX3FORM(xsnmaddasp, 0x04, 0x10, PPC2_VSX207), -GEN_XX3FORM(xsnmaddmsp, 0x04, 0x11, PPC2_VSX207), -GEN_XX3FORM(xsnmsubasp, 0x04, 0x12, PPC2_VSX207), -GEN_XX3FORM(xsnmsubmsp, 0x04, 0x13, PPC2_VSX207), -GEN_XX2FORM(xscvsxdsp, 0x10, 0x13, PPC2_VSX207), -GEN_XX2FORM(xscvuxdsp, 0x10, 0x12, PPC2_VSX207), - -GEN_XX3FORM(xvadddp, 0x00, 0x0C, PPC2_VSX), -GEN_XX3FORM(xvsubdp, 0x00, 0x0D, PPC2_VSX), -GEN_XX3FORM(xvmuldp, 0x00, 0x0E, PPC2_VSX), -GEN_XX3FORM(xvdivdp, 0x00, 0x0F, PPC2_VSX), -GEN_XX2FORM(xvredp, 0x14, 0x0D, PPC2_VSX), -GEN_XX2FORM(xvsqrtdp, 0x16, 0x0C, PPC2_VSX), -GEN_XX2FORM(xvrsqrtedp, 0x14, 0x0C, PPC2_VSX), -GEN_XX3FORM(xvtdivdp, 0x14, 0x0F, PPC2_VSX), -GEN_XX2FORM(xvtsqrtdp, 0x14, 0x0E, PPC2_VSX), -GEN_XX3FORM(xvmaddadp, 0x04, 0x0C, PPC2_VSX), -GEN_XX3FORM(xvmaddmdp, 0x04, 0x0D, PPC2_VSX), -GEN_XX3FORM(xvmsubadp, 0x04, 0x0E, PPC2_VSX), -GEN_XX3FORM(xvmsubmdp, 0x04, 0x0F, PPC2_VSX), -GEN_XX3FORM(xvnmaddadp, 0x04, 0x1C, PPC2_VSX), -GEN_XX3FORM(xvnmaddmdp, 0x04, 0x1D, PPC2_VSX), -GEN_XX3FORM(xvnmsubadp, 0x04, 0x1E, PPC2_VSX), -GEN_XX3FORM(xvnmsubmdp, 0x04, 0x1F, PPC2_VSX), -GEN_XX3FORM(xvmaxdp, 0x00, 0x1C, PPC2_VSX), -GEN_XX3FORM(xvmindp, 0x00, 0x1D, PPC2_VSX), -GEN_XX3_RC_FORM(xvcmpeqdp, 0x0C, 0x0C, PPC2_VSX), -GEN_XX3_RC_FORM(xvcmpgtdp, 0x0C, 0x0D, PPC2_VSX), -GEN_XX3_RC_FORM(xvcmpgedp, 0x0C, 0x0E, PPC2_VSX), -GEN_XX2FORM(xvcvdpsp, 0x12, 0x18, PPC2_VSX), -GEN_XX2FORM(xvcvdpsxds, 0x10, 0x1D, PPC2_VSX), -GEN_XX2FORM(xvcvdpsxws, 0x10, 0x0D, PPC2_VSX), -GEN_XX2FORM(xvcvdpuxds, 0x10, 0x1C, PPC2_VSX), -GEN_XX2FORM(xvcvdpuxws, 0x10, 0x0C, PPC2_VSX), -GEN_XX2FORM(xvcvsxddp, 0x10, 0x1F, PPC2_VSX), -GEN_XX2FORM(xvcvuxddp, 0x10, 0x1E, PPC2_VSX), -GEN_XX2FORM(xvcvsxwdp, 0x10, 0x0F, PPC2_VSX), -GEN_XX2FORM(xvcvuxwdp, 0x10, 0x0E, PPC2_VSX), -GEN_XX2FORM(xvrdpi, 0x12, 0x0C, PPC2_VSX), -GEN_XX2FORM(xvrdpic, 0x16, 0x0E, PPC2_VSX), -GEN_XX2FORM(xvrdpim, 0x12, 0x0F, PPC2_VSX), -GEN_XX2FORM(xvrdpip, 0x12, 0x0E, PPC2_VSX), -GEN_XX2FORM(xvrdpiz, 0x12, 0x0D, PPC2_VSX), - -GEN_XX3FORM(xvaddsp, 0x00, 0x08, PPC2_VSX), -GEN_XX3FORM(xvsubsp, 0x00, 0x09, PPC2_VSX), -GEN_XX3FORM(xvmulsp, 0x00, 0x0A, PPC2_VSX), -GEN_XX3FORM(xvdivsp, 0x00, 0x0B, PPC2_VSX), -GEN_XX2FORM(xvresp, 0x14, 0x09, PPC2_VSX), -GEN_XX2FORM(xvsqrtsp, 0x16, 0x08, PPC2_VSX), -GEN_XX2FORM(xvrsqrtesp, 0x14, 0x08, PPC2_VSX), -GEN_XX3FORM(xvtdivsp, 0x14, 0x0B, PPC2_VSX), -GEN_XX2FORM(xvtsqrtsp, 0x14, 0x0A, PPC2_VSX), -GEN_XX3FORM(xvmaddasp, 0x04, 0x08, PPC2_VSX), -GEN_XX3FORM(xvmaddmsp, 0x04, 0x09, PPC2_VSX), -GEN_XX3FORM(xvmsubasp, 0x04, 0x0A, PPC2_VSX), -GEN_XX3FORM(xvmsubmsp, 0x04, 0x0B, PPC2_VSX), -GEN_XX3FORM(xvnmaddasp, 0x04, 0x18, PPC2_VSX), -GEN_XX3FORM(xvnmaddmsp, 0x04, 0x19, PPC2_VSX), -GEN_XX3FORM(xvnmsubasp, 0x04, 0x1A, PPC2_VSX), -GEN_XX3FORM(xvnmsubmsp, 0x04, 0x1B, PPC2_VSX), -GEN_XX3FORM(xvmaxsp, 0x00, 0x18, PPC2_VSX), -GEN_XX3FORM(xvminsp, 0x00, 0x19, PPC2_VSX), -GEN_XX3_RC_FORM(xvcmpeqsp, 0x0C, 0x08, PPC2_VSX), -GEN_XX3_RC_FORM(xvcmpgtsp, 0x0C, 0x09, PPC2_VSX), -GEN_XX3_RC_FORM(xvcmpgesp, 0x0C, 0x0A, PPC2_VSX), -GEN_XX2FORM(xvcvspdp, 0x12, 0x1C, PPC2_VSX), -GEN_XX2FORM(xvcvspsxds, 0x10, 0x19, PPC2_VSX), -GEN_XX2FORM(xvcvspsxws, 0x10, 0x09, PPC2_VSX), -GEN_XX2FORM(xvcvspuxds, 0x10, 0x18, PPC2_VSX), -GEN_XX2FORM(xvcvspuxws, 0x10, 0x08, PPC2_VSX), -GEN_XX2FORM(xvcvsxdsp, 0x10, 0x1B, PPC2_VSX), -GEN_XX2FORM(xvcvuxdsp, 0x10, 0x1A, PPC2_VSX), -GEN_XX2FORM(xvcvsxwsp, 0x10, 0x0B, PPC2_VSX), -GEN_XX2FORM(xvcvuxwsp, 0x10, 0x0A, PPC2_VSX), -GEN_XX2FORM(xvrspi, 0x12, 0x08, PPC2_VSX), -GEN_XX2FORM(xvrspic, 0x16, 0x0A, PPC2_VSX), -GEN_XX2FORM(xvrspim, 0x12, 0x0B, PPC2_VSX), -GEN_XX2FORM(xvrspip, 0x12, 0x0A, PPC2_VSX), -GEN_XX2FORM(xvrspiz, 0x12, 0x09, PPC2_VSX), - -#undef VSX_LOGICAL -#define VSX_LOGICAL(name, opc2, opc3, fl2) \ -GEN_XX3FORM(name, opc2, opc3, fl2) - -VSX_LOGICAL(xxland, 0x8, 0x10, PPC2_VSX), -VSX_LOGICAL(xxlandc, 0x8, 0x11, PPC2_VSX), -VSX_LOGICAL(xxlor, 0x8, 0x12, PPC2_VSX), -VSX_LOGICAL(xxlxor, 0x8, 0x13, PPC2_VSX), -VSX_LOGICAL(xxlnor, 0x8, 0x14, PPC2_VSX), -VSX_LOGICAL(xxleqv, 0x8, 0x17, PPC2_VSX207), -VSX_LOGICAL(xxlnand, 0x8, 0x16, PPC2_VSX207), -VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207), -GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX), -GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX), -GEN_XX2FORM(xxspltw, 0x08, 0x0A, PPC2_VSX), -GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00), - -#define GEN_XXSEL_ROW(opc3) \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x18, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x19, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1A, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1B, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1C, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1D, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1E, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1F, opc3, 0, PPC_NONE, PPC2_VSX), \ - -GEN_XXSEL_ROW(0x00) -GEN_XXSEL_ROW(0x01) -GEN_XXSEL_ROW(0x02) -GEN_XXSEL_ROW(0x03) -GEN_XXSEL_ROW(0x04) -GEN_XXSEL_ROW(0x05) -GEN_XXSEL_ROW(0x06) -GEN_XXSEL_ROW(0x07) -GEN_XXSEL_ROW(0x08) -GEN_XXSEL_ROW(0x09) -GEN_XXSEL_ROW(0x0A) -GEN_XXSEL_ROW(0x0B) -GEN_XXSEL_ROW(0x0C) -GEN_XXSEL_ROW(0x0D) -GEN_XXSEL_ROW(0x0E) -GEN_XXSEL_ROW(0x0F) -GEN_XXSEL_ROW(0x10) -GEN_XXSEL_ROW(0x11) -GEN_XXSEL_ROW(0x12) -GEN_XXSEL_ROW(0x13) -GEN_XXSEL_ROW(0x14) -GEN_XXSEL_ROW(0x15) -GEN_XXSEL_ROW(0x16) -GEN_XXSEL_ROW(0x17) -GEN_XXSEL_ROW(0x18) -GEN_XXSEL_ROW(0x19) -GEN_XXSEL_ROW(0x1A) -GEN_XXSEL_ROW(0x1B) -GEN_XXSEL_ROW(0x1C) -GEN_XXSEL_ROW(0x1D) -GEN_XXSEL_ROW(0x1E) -GEN_XXSEL_ROW(0x1F) - -GEN_XX3FORM_DM(xxpermdi, 0x08, 0x01), +#include "translate/vsx-ops.c" #include "translate/dfp-ops.c" diff --git a/target-ppc/translate/vsx-impl.c b/target-ppc/translate/vsx-impl.c new file mode 100644 index 0000000000..7361c4779c --- /dev/null +++ b/target-ppc/translate/vsx-impl.c @@ -0,0 +1,721 @@ +/*** VSX extension ***/ + +static inline TCGv_i64 cpu_vsrh(int n) +{ + if (n < 32) { + return cpu_fpr[n]; + } else { + return cpu_avrh[n-32]; + } +} + +static inline TCGv_i64 cpu_vsrl(int n) +{ + if (n < 32) { + return cpu_vsr[n]; + } else { + return cpu_avrl[n-32]; + } +} + +#define VSX_LOAD_SCALAR(name, operation) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_INT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + gen_qemu_##operation(ctx, cpu_vsrh(xT(ctx->opcode)), EA); \ + /* NOTE: cpu_vsrl is undefined */ \ + tcg_temp_free(EA); \ +} + +VSX_LOAD_SCALAR(lxsdx, ld64) +VSX_LOAD_SCALAR(lxsiwax, ld32s_i64) +VSX_LOAD_SCALAR(lxsiwzx, ld32u_i64) +VSX_LOAD_SCALAR(lxsspx, ld32fs) + +static void gen_lxvd2x(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_ld64(ctx, cpu_vsrl(xT(ctx->opcode)), EA); + tcg_temp_free(EA); +} + +static void gen_lxvdsx(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode))); + tcg_temp_free(EA); +} + +static void gen_lxvw4x(DisasContext *ctx) +{ + TCGv EA; + TCGv_i64 tmp; + TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); + TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + tmp = tcg_temp_new_i64(); + + gen_addr_reg_index(ctx, EA); + gen_qemu_ld32u_i64(ctx, tmp, EA); + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_ld32u_i64(ctx, xth, EA); + tcg_gen_deposit_i64(xth, xth, tmp, 32, 32); + + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_ld32u_i64(ctx, tmp, EA); + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_ld32u_i64(ctx, xtl, EA); + tcg_gen_deposit_i64(xtl, xtl, tmp, 32, 32); + + tcg_temp_free(EA); + tcg_temp_free_i64(tmp); +} + +#define VSX_STORE_SCALAR(name, operation) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv EA; \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + gen_set_access_type(ctx, ACCESS_INT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + gen_qemu_##operation(ctx, cpu_vsrh(xS(ctx->opcode)), EA); \ + tcg_temp_free(EA); \ +} + +VSX_STORE_SCALAR(stxsdx, st64) +VSX_STORE_SCALAR(stxsiwx, st32_i64) +VSX_STORE_SCALAR(stxsspx, st32fs) + +static void gen_stxvd2x(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + gen_qemu_st64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_st64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); + tcg_temp_free(EA); +} + +static void gen_stxvw4x(DisasContext *ctx) +{ + TCGv_i64 tmp; + TCGv EA; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tmp = tcg_temp_new_i64(); + + tcg_gen_shri_i64(tmp, cpu_vsrh(xS(ctx->opcode)), 32); + gen_qemu_st32_i64(ctx, tmp, EA); + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_st32_i64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); + + tcg_gen_shri_i64(tmp, cpu_vsrl(xS(ctx->opcode)), 32); + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_st32_i64(ctx, tmp, EA); + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_st32_i64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); + + tcg_temp_free(EA); + tcg_temp_free_i64(tmp); +} + +#define MV_VSRW(name, tcgop1, tcgop2, target, source) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + if (xS(ctx->opcode) < 32) { \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + } else { \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + } \ + TCGv_i64 tmp = tcg_temp_new_i64(); \ + tcg_gen_##tcgop1(tmp, source); \ + tcg_gen_##tcgop2(target, tmp); \ + tcg_temp_free_i64(tmp); \ +} + + +MV_VSRW(mfvsrwz, ext32u_i64, trunc_i64_tl, cpu_gpr[rA(ctx->opcode)], \ + cpu_vsrh(xS(ctx->opcode))) +MV_VSRW(mtvsrwa, extu_tl_i64, ext32s_i64, cpu_vsrh(xT(ctx->opcode)), \ + cpu_gpr[rA(ctx->opcode)]) +MV_VSRW(mtvsrwz, extu_tl_i64, ext32u_i64, cpu_vsrh(xT(ctx->opcode)), \ + cpu_gpr[rA(ctx->opcode)]) + +#if defined(TARGET_PPC64) +#define MV_VSRD(name, target, source) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + if (xS(ctx->opcode) < 32) { \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + } else { \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + } \ + tcg_gen_mov_i64(target, source); \ +} + +MV_VSRD(mfvsrd, cpu_gpr[rA(ctx->opcode)], cpu_vsrh(xS(ctx->opcode))) +MV_VSRD(mtvsrd, cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)]) + +#endif + +static void gen_xxpermdi(DisasContext *ctx) +{ + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + + if (unlikely((xT(ctx->opcode) == xA(ctx->opcode)) || + (xT(ctx->opcode) == xB(ctx->opcode)))) { + TCGv_i64 xh, xl; + + xh = tcg_temp_new_i64(); + xl = tcg_temp_new_i64(); + + if ((DM(ctx->opcode) & 2) == 0) { + tcg_gen_mov_i64(xh, cpu_vsrh(xA(ctx->opcode))); + } else { + tcg_gen_mov_i64(xh, cpu_vsrl(xA(ctx->opcode))); + } + if ((DM(ctx->opcode) & 1) == 0) { + tcg_gen_mov_i64(xl, cpu_vsrh(xB(ctx->opcode))); + } else { + tcg_gen_mov_i64(xl, cpu_vsrl(xB(ctx->opcode))); + } + + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xh); + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xl); + + tcg_temp_free_i64(xh); + tcg_temp_free_i64(xl); + } else { + if ((DM(ctx->opcode) & 2) == 0) { + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode))); + } else { + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode))); + } + if ((DM(ctx->opcode) & 1) == 0) { + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xB(ctx->opcode))); + } else { + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xB(ctx->opcode))); + } + } +} + +#define OP_ABS 1 +#define OP_NABS 2 +#define OP_NEG 3 +#define OP_CPSGN 4 +#define SGN_MASK_DP 0x8000000000000000ull +#define SGN_MASK_SP 0x8000000080000000ull + +#define VSX_SCALAR_MOVE(name, op, sgn_mask) \ +static void glue(gen_, name)(DisasContext * ctx) \ + { \ + TCGv_i64 xb, sgm; \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + xb = tcg_temp_new_i64(); \ + sgm = tcg_temp_new_i64(); \ + tcg_gen_mov_i64(xb, cpu_vsrh(xB(ctx->opcode))); \ + tcg_gen_movi_i64(sgm, sgn_mask); \ + switch (op) { \ + case OP_ABS: { \ + tcg_gen_andc_i64(xb, xb, sgm); \ + break; \ + } \ + case OP_NABS: { \ + tcg_gen_or_i64(xb, xb, sgm); \ + break; \ + } \ + case OP_NEG: { \ + tcg_gen_xor_i64(xb, xb, sgm); \ + break; \ + } \ + case OP_CPSGN: { \ + TCGv_i64 xa = tcg_temp_new_i64(); \ + tcg_gen_mov_i64(xa, cpu_vsrh(xA(ctx->opcode))); \ + tcg_gen_and_i64(xa, xa, sgm); \ + tcg_gen_andc_i64(xb, xb, sgm); \ + tcg_gen_or_i64(xb, xb, xa); \ + tcg_temp_free_i64(xa); \ + break; \ + } \ + } \ + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xb); \ + tcg_temp_free_i64(xb); \ + tcg_temp_free_i64(sgm); \ + } + +VSX_SCALAR_MOVE(xsabsdp, OP_ABS, SGN_MASK_DP) +VSX_SCALAR_MOVE(xsnabsdp, OP_NABS, SGN_MASK_DP) +VSX_SCALAR_MOVE(xsnegdp, OP_NEG, SGN_MASK_DP) +VSX_SCALAR_MOVE(xscpsgndp, OP_CPSGN, SGN_MASK_DP) + +#define VSX_VECTOR_MOVE(name, op, sgn_mask) \ +static void glue(gen_, name)(DisasContext * ctx) \ + { \ + TCGv_i64 xbh, xbl, sgm; \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + xbh = tcg_temp_new_i64(); \ + xbl = tcg_temp_new_i64(); \ + sgm = tcg_temp_new_i64(); \ + tcg_gen_mov_i64(xbh, cpu_vsrh(xB(ctx->opcode))); \ + tcg_gen_mov_i64(xbl, cpu_vsrl(xB(ctx->opcode))); \ + tcg_gen_movi_i64(sgm, sgn_mask); \ + switch (op) { \ + case OP_ABS: { \ + tcg_gen_andc_i64(xbh, xbh, sgm); \ + tcg_gen_andc_i64(xbl, xbl, sgm); \ + break; \ + } \ + case OP_NABS: { \ + tcg_gen_or_i64(xbh, xbh, sgm); \ + tcg_gen_or_i64(xbl, xbl, sgm); \ + break; \ + } \ + case OP_NEG: { \ + tcg_gen_xor_i64(xbh, xbh, sgm); \ + tcg_gen_xor_i64(xbl, xbl, sgm); \ + break; \ + } \ + case OP_CPSGN: { \ + TCGv_i64 xah = tcg_temp_new_i64(); \ + TCGv_i64 xal = tcg_temp_new_i64(); \ + tcg_gen_mov_i64(xah, cpu_vsrh(xA(ctx->opcode))); \ + tcg_gen_mov_i64(xal, cpu_vsrl(xA(ctx->opcode))); \ + tcg_gen_and_i64(xah, xah, sgm); \ + tcg_gen_and_i64(xal, xal, sgm); \ + tcg_gen_andc_i64(xbh, xbh, sgm); \ + tcg_gen_andc_i64(xbl, xbl, sgm); \ + tcg_gen_or_i64(xbh, xbh, xah); \ + tcg_gen_or_i64(xbl, xbl, xal); \ + tcg_temp_free_i64(xah); \ + tcg_temp_free_i64(xal); \ + break; \ + } \ + } \ + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xbh); \ + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xbl); \ + tcg_temp_free_i64(xbh); \ + tcg_temp_free_i64(xbl); \ + tcg_temp_free_i64(sgm); \ + } + +VSX_VECTOR_MOVE(xvabsdp, OP_ABS, SGN_MASK_DP) +VSX_VECTOR_MOVE(xvnabsdp, OP_NABS, SGN_MASK_DP) +VSX_VECTOR_MOVE(xvnegdp, OP_NEG, SGN_MASK_DP) +VSX_VECTOR_MOVE(xvcpsgndp, OP_CPSGN, SGN_MASK_DP) +VSX_VECTOR_MOVE(xvabssp, OP_ABS, SGN_MASK_SP) +VSX_VECTOR_MOVE(xvnabssp, OP_NABS, SGN_MASK_SP) +VSX_VECTOR_MOVE(xvnegsp, OP_NEG, SGN_MASK_SP) +VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP) + +#define GEN_VSX_HELPER_2(name, op1, op2, inval, type) \ +static void gen_##name(DisasContext * ctx) \ +{ \ + TCGv_i32 opc; \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + /* NIP cannot be restored if the memory exception comes from an helper */ \ + gen_update_nip(ctx, ctx->nip - 4); \ + opc = tcg_const_i32(ctx->opcode); \ + gen_helper_##name(cpu_env, opc); \ + tcg_temp_free_i32(opc); \ +} + +#define GEN_VSX_HELPER_XT_XB_ENV(name, op1, op2, inval, type) \ +static void gen_##name(DisasContext * ctx) \ +{ \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + /* NIP cannot be restored if the exception comes */ \ + /* from a helper. */ \ + gen_update_nip(ctx, ctx->nip - 4); \ + \ + gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env, \ + cpu_vsrh(xB(ctx->opcode))); \ +} + +GEN_VSX_HELPER_2(xsadddp, 0x00, 0x04, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xssubdp, 0x00, 0x05, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsmuldp, 0x00, 0x06, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsdivdp, 0x00, 0x07, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsredp, 0x14, 0x05, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xssqrtdp, 0x16, 0x04, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsrsqrtedp, 0x14, 0x04, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xstdivdp, 0x14, 0x07, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xstsqrtdp, 0x14, 0x06, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsmaddadp, 0x04, 0x04, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsmaddmdp, 0x04, 0x05, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsmsubadp, 0x04, 0x06, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsmsubmdp, 0x04, 0x07, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsnmaddadp, 0x04, 0x14, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsnmaddmdp, 0x04, 0x15, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsnmsubadp, 0x04, 0x16, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsnmsubmdp, 0x04, 0x17, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xscmpodp, 0x0C, 0x05, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xscmpudp, 0x0C, 0x04, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsmindp, 0x00, 0x15, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX) +GEN_VSX_HELPER_XT_XB_ENV(xscvdpspn, 0x16, 0x10, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX) +GEN_VSX_HELPER_XT_XB_ENV(xscvspdpn, 0x16, 0x14, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xscvdpsxds, 0x10, 0x15, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xscvdpsxws, 0x10, 0x05, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xscvdpuxds, 0x10, 0x14, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xscvdpuxws, 0x10, 0x04, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xscvsxddp, 0x10, 0x17, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xscvuxddp, 0x10, 0x16, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsrdpi, 0x12, 0x04, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsrdpic, 0x16, 0x06, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsrdpim, 0x12, 0x07, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsrdpip, 0x12, 0x06, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xsrdpiz, 0x12, 0x05, 0, PPC2_VSX) +GEN_VSX_HELPER_XT_XB_ENV(xsrsp, 0x12, 0x11, 0, PPC2_VSX207) + +GEN_VSX_HELPER_2(xsaddsp, 0x00, 0x00, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xssubsp, 0x00, 0x01, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsmulsp, 0x00, 0x02, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsdivsp, 0x00, 0x03, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsresp, 0x14, 0x01, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsmaddasp, 0x04, 0x00, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsmaddmsp, 0x04, 0x01, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsmsubasp, 0x04, 0x02, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsmsubmsp, 0x04, 0x03, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsnmaddasp, 0x04, 0x10, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsnmaddmsp, 0x04, 0x11, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsnmsubasp, 0x04, 0x12, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xsnmsubmsp, 0x04, 0x13, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207) +GEN_VSX_HELPER_2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207) + +GEN_VSX_HELPER_2(xvadddp, 0x00, 0x0C, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmuldp, 0x00, 0x0E, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvdivdp, 0x00, 0x0F, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvredp, 0x14, 0x0D, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvsqrtdp, 0x16, 0x0C, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrsqrtedp, 0x14, 0x0C, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvtdivdp, 0x14, 0x0F, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvtsqrtdp, 0x14, 0x0E, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmaddadp, 0x04, 0x0C, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmaddmdp, 0x04, 0x0D, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmsubadp, 0x04, 0x0E, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmsubmdp, 0x04, 0x0F, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvnmaddadp, 0x04, 0x1C, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvnmaddmdp, 0x04, 0x1D, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvnmsubadp, 0x04, 0x1E, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvnmsubmdp, 0x04, 0x1F, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmaxdp, 0x00, 0x1C, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmindp, 0x00, 0x1D, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcmpeqdp, 0x0C, 0x0C, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcmpgtdp, 0x0C, 0x0D, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcmpgedp, 0x0C, 0x0E, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvdpsp, 0x12, 0x18, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvdpsxds, 0x10, 0x1D, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvdpsxws, 0x10, 0x0D, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvdpuxds, 0x10, 0x1C, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvdpuxws, 0x10, 0x0C, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvsxddp, 0x10, 0x1F, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvuxddp, 0x10, 0x1E, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvsxwdp, 0x10, 0x0F, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvuxwdp, 0x10, 0x0E, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrdpi, 0x12, 0x0C, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrdpic, 0x16, 0x0E, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrdpim, 0x12, 0x0F, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrdpip, 0x12, 0x0E, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrdpiz, 0x12, 0x0D, 0, PPC2_VSX) + +GEN_VSX_HELPER_2(xvaddsp, 0x00, 0x08, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvsubsp, 0x00, 0x09, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmulsp, 0x00, 0x0A, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvdivsp, 0x00, 0x0B, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvresp, 0x14, 0x09, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvsqrtsp, 0x16, 0x08, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrsqrtesp, 0x14, 0x08, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvtdivsp, 0x14, 0x0B, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvtsqrtsp, 0x14, 0x0A, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmaddasp, 0x04, 0x08, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmaddmsp, 0x04, 0x09, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmsubasp, 0x04, 0x0A, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmsubmsp, 0x04, 0x0B, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvnmaddasp, 0x04, 0x18, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvnmaddmsp, 0x04, 0x19, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvnmsubasp, 0x04, 0x1A, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvnmsubmsp, 0x04, 0x1B, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvmaxsp, 0x00, 0x18, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvminsp, 0x00, 0x19, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcmpeqsp, 0x0C, 0x08, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcmpgtsp, 0x0C, 0x09, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcmpgesp, 0x0C, 0x0A, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvspdp, 0x12, 0x1C, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvspsxds, 0x10, 0x19, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvspsxws, 0x10, 0x09, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvspuxds, 0x10, 0x18, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvspuxws, 0x10, 0x08, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvsxdsp, 0x10, 0x1B, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvuxdsp, 0x10, 0x1A, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvsxwsp, 0x10, 0x0B, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvcvuxwsp, 0x10, 0x0A, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrspi, 0x12, 0x08, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrspic, 0x16, 0x0A, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrspim, 0x12, 0x0B, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrspip, 0x12, 0x0A, 0, PPC2_VSX) +GEN_VSX_HELPER_2(xvrspiz, 0x12, 0x09, 0, PPC2_VSX) + +#define VSX_LOGICAL(name, tcg_op) \ +static void glue(gen_, name)(DisasContext * ctx) \ + { \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + tcg_op(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode)), \ + cpu_vsrh(xB(ctx->opcode))); \ + tcg_op(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode)), \ + cpu_vsrl(xB(ctx->opcode))); \ + } + +VSX_LOGICAL(xxland, tcg_gen_and_i64) +VSX_LOGICAL(xxlandc, tcg_gen_andc_i64) +VSX_LOGICAL(xxlor, tcg_gen_or_i64) +VSX_LOGICAL(xxlxor, tcg_gen_xor_i64) +VSX_LOGICAL(xxlnor, tcg_gen_nor_i64) +VSX_LOGICAL(xxleqv, tcg_gen_eqv_i64) +VSX_LOGICAL(xxlnand, tcg_gen_nand_i64) +VSX_LOGICAL(xxlorc, tcg_gen_orc_i64) + +#define VSX_XXMRG(name, high) \ +static void glue(gen_, name)(DisasContext * ctx) \ + { \ + TCGv_i64 a0, a1, b0, b1; \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + a0 = tcg_temp_new_i64(); \ + a1 = tcg_temp_new_i64(); \ + b0 = tcg_temp_new_i64(); \ + b1 = tcg_temp_new_i64(); \ + if (high) { \ + tcg_gen_mov_i64(a0, cpu_vsrh(xA(ctx->opcode))); \ + tcg_gen_mov_i64(a1, cpu_vsrh(xA(ctx->opcode))); \ + tcg_gen_mov_i64(b0, cpu_vsrh(xB(ctx->opcode))); \ + tcg_gen_mov_i64(b1, cpu_vsrh(xB(ctx->opcode))); \ + } else { \ + tcg_gen_mov_i64(a0, cpu_vsrl(xA(ctx->opcode))); \ + tcg_gen_mov_i64(a1, cpu_vsrl(xA(ctx->opcode))); \ + tcg_gen_mov_i64(b0, cpu_vsrl(xB(ctx->opcode))); \ + tcg_gen_mov_i64(b1, cpu_vsrl(xB(ctx->opcode))); \ + } \ + tcg_gen_shri_i64(a0, a0, 32); \ + tcg_gen_shri_i64(b0, b0, 32); \ + tcg_gen_deposit_i64(cpu_vsrh(xT(ctx->opcode)), \ + b0, a0, 32, 32); \ + tcg_gen_deposit_i64(cpu_vsrl(xT(ctx->opcode)), \ + b1, a1, 32, 32); \ + tcg_temp_free_i64(a0); \ + tcg_temp_free_i64(a1); \ + tcg_temp_free_i64(b0); \ + tcg_temp_free_i64(b1); \ + } + +VSX_XXMRG(xxmrghw, 1) +VSX_XXMRG(xxmrglw, 0) + +static void gen_xxsel(DisasContext * ctx) +{ + TCGv_i64 a, b, c; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + a = tcg_temp_new_i64(); + b = tcg_temp_new_i64(); + c = tcg_temp_new_i64(); + + tcg_gen_mov_i64(a, cpu_vsrh(xA(ctx->opcode))); + tcg_gen_mov_i64(b, cpu_vsrh(xB(ctx->opcode))); + tcg_gen_mov_i64(c, cpu_vsrh(xC(ctx->opcode))); + + tcg_gen_and_i64(b, b, c); + tcg_gen_andc_i64(a, a, c); + tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), a, b); + + tcg_gen_mov_i64(a, cpu_vsrl(xA(ctx->opcode))); + tcg_gen_mov_i64(b, cpu_vsrl(xB(ctx->opcode))); + tcg_gen_mov_i64(c, cpu_vsrl(xC(ctx->opcode))); + + tcg_gen_and_i64(b, b, c); + tcg_gen_andc_i64(a, a, c); + tcg_gen_or_i64(cpu_vsrl(xT(ctx->opcode)), a, b); + + tcg_temp_free_i64(a); + tcg_temp_free_i64(b); + tcg_temp_free_i64(c); +} + +static void gen_xxspltw(DisasContext *ctx) +{ + TCGv_i64 b, b2; + TCGv_i64 vsr = (UIM(ctx->opcode) & 2) ? + cpu_vsrl(xB(ctx->opcode)) : + cpu_vsrh(xB(ctx->opcode)); + + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + + b = tcg_temp_new_i64(); + b2 = tcg_temp_new_i64(); + + if (UIM(ctx->opcode) & 1) { + tcg_gen_ext32u_i64(b, vsr); + } else { + tcg_gen_shri_i64(b, vsr, 32); + } + + tcg_gen_shli_i64(b2, b, 32); + tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), b, b2); + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode))); + + tcg_temp_free_i64(b); + tcg_temp_free_i64(b2); +} + +static void gen_xxsldwi(DisasContext *ctx) +{ + TCGv_i64 xth, xtl; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + + switch (SHW(ctx->opcode)) { + case 0: { + tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode))); + tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode))); + break; + } + case 1: { + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode))); + tcg_gen_shli_i64(xth, xth, 32); + tcg_gen_mov_i64(t0, cpu_vsrl(xA(ctx->opcode))); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_or_i64(xth, xth, t0); + tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode))); + tcg_gen_shli_i64(xtl, xtl, 32); + tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode))); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_or_i64(xtl, xtl, t0); + tcg_temp_free_i64(t0); + break; + } + case 2: { + tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode))); + tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode))); + break; + } + case 3: { + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode))); + tcg_gen_shli_i64(xth, xth, 32); + tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode))); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_or_i64(xth, xth, t0); + tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode))); + tcg_gen_shli_i64(xtl, xtl, 32); + tcg_gen_mov_i64(t0, cpu_vsrl(xB(ctx->opcode))); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_or_i64(xtl, xtl, t0); + tcg_temp_free_i64(t0); + break; + } + } + + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xth); + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xtl); + + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); +} + +#undef GEN_XX2FORM +#undef GEN_XX3FORM +#undef GEN_XX2IFORM +#undef GEN_XX3_RC_FORM +#undef GEN_XX3FORM_DM +#undef VSX_LOGICAL diff --git a/target-ppc/translate/vsx-ops.c b/target-ppc/translate/vsx-ops.c new file mode 100644 index 0000000000..8b9da65444 --- /dev/null +++ b/target-ppc/translate/vsx-ops.c @@ -0,0 +1,270 @@ +GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(lxsiwax, 0x1F, 0x0C, 0x02, 0, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(lxsiwzx, 0x1F, 0x0C, 0x00, 0, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX), + +GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX), + +GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(mtvsrwz, 0x1F, 0x13, 0x07, 0x0000F800, PPC_NONE, PPC2_VSX207), +#if defined(TARGET_PPC64) +GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207), +#endif + +#define GEN_XX2FORM(name, opc2, opc3, fl2) \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2) + +#define GEN_XX3FORM(name, opc2, opc3, fl2) \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 0, PPC_NONE, fl2) + +#define GEN_XX2IFORM(name, opc2, opc3, fl2) \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 1, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 1, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 1, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 1, PPC_NONE, fl2) + +#define GEN_XX3_RC_FORM(name, opc2, opc3, fl2) \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x00, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x00, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x00, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x00, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x10, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x10, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x10, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x10, 0, PPC_NONE, fl2) + +#define GEN_XX3FORM_DM(name, opc2, opc3) \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x0C, 0, PPC_NONE, PPC2_VSX) + +GEN_XX2FORM(xsabsdp, 0x12, 0x15, PPC2_VSX), +GEN_XX2FORM(xsnabsdp, 0x12, 0x16, PPC2_VSX), +GEN_XX2FORM(xsnegdp, 0x12, 0x17, PPC2_VSX), +GEN_XX3FORM(xscpsgndp, 0x00, 0x16, PPC2_VSX), + +GEN_XX2FORM(xvabsdp, 0x12, 0x1D, PPC2_VSX), +GEN_XX2FORM(xvnabsdp, 0x12, 0x1E, PPC2_VSX), +GEN_XX2FORM(xvnegdp, 0x12, 0x1F, PPC2_VSX), +GEN_XX3FORM(xvcpsgndp, 0x00, 0x1E, PPC2_VSX), +GEN_XX2FORM(xvabssp, 0x12, 0x19, PPC2_VSX), +GEN_XX2FORM(xvnabssp, 0x12, 0x1A, PPC2_VSX), +GEN_XX2FORM(xvnegsp, 0x12, 0x1B, PPC2_VSX), +GEN_XX3FORM(xvcpsgnsp, 0x00, 0x1A, PPC2_VSX), + +GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX), +GEN_XX3FORM(xssubdp, 0x00, 0x05, PPC2_VSX), +GEN_XX3FORM(xsmuldp, 0x00, 0x06, PPC2_VSX), +GEN_XX3FORM(xsdivdp, 0x00, 0x07, PPC2_VSX), +GEN_XX2FORM(xsredp, 0x14, 0x05, PPC2_VSX), +GEN_XX2FORM(xssqrtdp, 0x16, 0x04, PPC2_VSX), +GEN_XX2FORM(xsrsqrtedp, 0x14, 0x04, PPC2_VSX), +GEN_XX3FORM(xstdivdp, 0x14, 0x07, PPC2_VSX), +GEN_XX2FORM(xstsqrtdp, 0x14, 0x06, PPC2_VSX), +GEN_XX3FORM(xsmaddadp, 0x04, 0x04, PPC2_VSX), +GEN_XX3FORM(xsmaddmdp, 0x04, 0x05, PPC2_VSX), +GEN_XX3FORM(xsmsubadp, 0x04, 0x06, PPC2_VSX), +GEN_XX3FORM(xsmsubmdp, 0x04, 0x07, PPC2_VSX), +GEN_XX3FORM(xsnmaddadp, 0x04, 0x14, PPC2_VSX), +GEN_XX3FORM(xsnmaddmdp, 0x04, 0x15, PPC2_VSX), +GEN_XX3FORM(xsnmsubadp, 0x04, 0x16, PPC2_VSX), +GEN_XX3FORM(xsnmsubmdp, 0x04, 0x17, PPC2_VSX), +GEN_XX2IFORM(xscmpodp, 0x0C, 0x05, PPC2_VSX), +GEN_XX2IFORM(xscmpudp, 0x0C, 0x04, PPC2_VSX), +GEN_XX3FORM(xsmaxdp, 0x00, 0x14, PPC2_VSX), +GEN_XX3FORM(xsmindp, 0x00, 0x15, PPC2_VSX), +GEN_XX2FORM(xscvdpsp, 0x12, 0x10, PPC2_VSX), +GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207), +GEN_XX2FORM(xscvspdp, 0x12, 0x14, PPC2_VSX), +GEN_XX2FORM(xscvspdpn, 0x16, 0x14, PPC2_VSX207), +GEN_XX2FORM(xscvdpsxds, 0x10, 0x15, PPC2_VSX), +GEN_XX2FORM(xscvdpsxws, 0x10, 0x05, PPC2_VSX), +GEN_XX2FORM(xscvdpuxds, 0x10, 0x14, PPC2_VSX), +GEN_XX2FORM(xscvdpuxws, 0x10, 0x04, PPC2_VSX), +GEN_XX2FORM(xscvsxddp, 0x10, 0x17, PPC2_VSX), +GEN_XX2FORM(xscvuxddp, 0x10, 0x16, PPC2_VSX), +GEN_XX2FORM(xsrdpi, 0x12, 0x04, PPC2_VSX), +GEN_XX2FORM(xsrdpic, 0x16, 0x06, PPC2_VSX), +GEN_XX2FORM(xsrdpim, 0x12, 0x07, PPC2_VSX), +GEN_XX2FORM(xsrdpip, 0x12, 0x06, PPC2_VSX), +GEN_XX2FORM(xsrdpiz, 0x12, 0x05, PPC2_VSX), + +GEN_XX3FORM(xsaddsp, 0x00, 0x00, PPC2_VSX207), +GEN_XX3FORM(xssubsp, 0x00, 0x01, PPC2_VSX207), +GEN_XX3FORM(xsmulsp, 0x00, 0x02, PPC2_VSX207), +GEN_XX3FORM(xsdivsp, 0x00, 0x03, PPC2_VSX207), +GEN_XX2FORM(xsresp, 0x14, 0x01, PPC2_VSX207), +GEN_XX2FORM(xsrsp, 0x12, 0x11, PPC2_VSX207), +GEN_XX2FORM(xssqrtsp, 0x16, 0x00, PPC2_VSX207), +GEN_XX2FORM(xsrsqrtesp, 0x14, 0x00, PPC2_VSX207), +GEN_XX3FORM(xsmaddasp, 0x04, 0x00, PPC2_VSX207), +GEN_XX3FORM(xsmaddmsp, 0x04, 0x01, PPC2_VSX207), +GEN_XX3FORM(xsmsubasp, 0x04, 0x02, PPC2_VSX207), +GEN_XX3FORM(xsmsubmsp, 0x04, 0x03, PPC2_VSX207), +GEN_XX3FORM(xsnmaddasp, 0x04, 0x10, PPC2_VSX207), +GEN_XX3FORM(xsnmaddmsp, 0x04, 0x11, PPC2_VSX207), +GEN_XX3FORM(xsnmsubasp, 0x04, 0x12, PPC2_VSX207), +GEN_XX3FORM(xsnmsubmsp, 0x04, 0x13, PPC2_VSX207), +GEN_XX2FORM(xscvsxdsp, 0x10, 0x13, PPC2_VSX207), +GEN_XX2FORM(xscvuxdsp, 0x10, 0x12, PPC2_VSX207), + +GEN_XX3FORM(xvadddp, 0x00, 0x0C, PPC2_VSX), +GEN_XX3FORM(xvsubdp, 0x00, 0x0D, PPC2_VSX), +GEN_XX3FORM(xvmuldp, 0x00, 0x0E, PPC2_VSX), +GEN_XX3FORM(xvdivdp, 0x00, 0x0F, PPC2_VSX), +GEN_XX2FORM(xvredp, 0x14, 0x0D, PPC2_VSX), +GEN_XX2FORM(xvsqrtdp, 0x16, 0x0C, PPC2_VSX), +GEN_XX2FORM(xvrsqrtedp, 0x14, 0x0C, PPC2_VSX), +GEN_XX3FORM(xvtdivdp, 0x14, 0x0F, PPC2_VSX), +GEN_XX2FORM(xvtsqrtdp, 0x14, 0x0E, PPC2_VSX), +GEN_XX3FORM(xvmaddadp, 0x04, 0x0C, PPC2_VSX), +GEN_XX3FORM(xvmaddmdp, 0x04, 0x0D, PPC2_VSX), +GEN_XX3FORM(xvmsubadp, 0x04, 0x0E, PPC2_VSX), +GEN_XX3FORM(xvmsubmdp, 0x04, 0x0F, PPC2_VSX), +GEN_XX3FORM(xvnmaddadp, 0x04, 0x1C, PPC2_VSX), +GEN_XX3FORM(xvnmaddmdp, 0x04, 0x1D, PPC2_VSX), +GEN_XX3FORM(xvnmsubadp, 0x04, 0x1E, PPC2_VSX), +GEN_XX3FORM(xvnmsubmdp, 0x04, 0x1F, PPC2_VSX), +GEN_XX3FORM(xvmaxdp, 0x00, 0x1C, PPC2_VSX), +GEN_XX3FORM(xvmindp, 0x00, 0x1D, PPC2_VSX), +GEN_XX3_RC_FORM(xvcmpeqdp, 0x0C, 0x0C, PPC2_VSX), +GEN_XX3_RC_FORM(xvcmpgtdp, 0x0C, 0x0D, PPC2_VSX), +GEN_XX3_RC_FORM(xvcmpgedp, 0x0C, 0x0E, PPC2_VSX), +GEN_XX2FORM(xvcvdpsp, 0x12, 0x18, PPC2_VSX), +GEN_XX2FORM(xvcvdpsxds, 0x10, 0x1D, PPC2_VSX), +GEN_XX2FORM(xvcvdpsxws, 0x10, 0x0D, PPC2_VSX), +GEN_XX2FORM(xvcvdpuxds, 0x10, 0x1C, PPC2_VSX), +GEN_XX2FORM(xvcvdpuxws, 0x10, 0x0C, PPC2_VSX), +GEN_XX2FORM(xvcvsxddp, 0x10, 0x1F, PPC2_VSX), +GEN_XX2FORM(xvcvuxddp, 0x10, 0x1E, PPC2_VSX), +GEN_XX2FORM(xvcvsxwdp, 0x10, 0x0F, PPC2_VSX), +GEN_XX2FORM(xvcvuxwdp, 0x10, 0x0E, PPC2_VSX), +GEN_XX2FORM(xvrdpi, 0x12, 0x0C, PPC2_VSX), +GEN_XX2FORM(xvrdpic, 0x16, 0x0E, PPC2_VSX), +GEN_XX2FORM(xvrdpim, 0x12, 0x0F, PPC2_VSX), +GEN_XX2FORM(xvrdpip, 0x12, 0x0E, PPC2_VSX), +GEN_XX2FORM(xvrdpiz, 0x12, 0x0D, PPC2_VSX), + +GEN_XX3FORM(xvaddsp, 0x00, 0x08, PPC2_VSX), +GEN_XX3FORM(xvsubsp, 0x00, 0x09, PPC2_VSX), +GEN_XX3FORM(xvmulsp, 0x00, 0x0A, PPC2_VSX), +GEN_XX3FORM(xvdivsp, 0x00, 0x0B, PPC2_VSX), +GEN_XX2FORM(xvresp, 0x14, 0x09, PPC2_VSX), +GEN_XX2FORM(xvsqrtsp, 0x16, 0x08, PPC2_VSX), +GEN_XX2FORM(xvrsqrtesp, 0x14, 0x08, PPC2_VSX), +GEN_XX3FORM(xvtdivsp, 0x14, 0x0B, PPC2_VSX), +GEN_XX2FORM(xvtsqrtsp, 0x14, 0x0A, PPC2_VSX), +GEN_XX3FORM(xvmaddasp, 0x04, 0x08, PPC2_VSX), +GEN_XX3FORM(xvmaddmsp, 0x04, 0x09, PPC2_VSX), +GEN_XX3FORM(xvmsubasp, 0x04, 0x0A, PPC2_VSX), +GEN_XX3FORM(xvmsubmsp, 0x04, 0x0B, PPC2_VSX), +GEN_XX3FORM(xvnmaddasp, 0x04, 0x18, PPC2_VSX), +GEN_XX3FORM(xvnmaddmsp, 0x04, 0x19, PPC2_VSX), +GEN_XX3FORM(xvnmsubasp, 0x04, 0x1A, PPC2_VSX), +GEN_XX3FORM(xvnmsubmsp, 0x04, 0x1B, PPC2_VSX), +GEN_XX3FORM(xvmaxsp, 0x00, 0x18, PPC2_VSX), +GEN_XX3FORM(xvminsp, 0x00, 0x19, PPC2_VSX), +GEN_XX3_RC_FORM(xvcmpeqsp, 0x0C, 0x08, PPC2_VSX), +GEN_XX3_RC_FORM(xvcmpgtsp, 0x0C, 0x09, PPC2_VSX), +GEN_XX3_RC_FORM(xvcmpgesp, 0x0C, 0x0A, PPC2_VSX), +GEN_XX2FORM(xvcvspdp, 0x12, 0x1C, PPC2_VSX), +GEN_XX2FORM(xvcvspsxds, 0x10, 0x19, PPC2_VSX), +GEN_XX2FORM(xvcvspsxws, 0x10, 0x09, PPC2_VSX), +GEN_XX2FORM(xvcvspuxds, 0x10, 0x18, PPC2_VSX), +GEN_XX2FORM(xvcvspuxws, 0x10, 0x08, PPC2_VSX), +GEN_XX2FORM(xvcvsxdsp, 0x10, 0x1B, PPC2_VSX), +GEN_XX2FORM(xvcvuxdsp, 0x10, 0x1A, PPC2_VSX), +GEN_XX2FORM(xvcvsxwsp, 0x10, 0x0B, PPC2_VSX), +GEN_XX2FORM(xvcvuxwsp, 0x10, 0x0A, PPC2_VSX), +GEN_XX2FORM(xvrspi, 0x12, 0x08, PPC2_VSX), +GEN_XX2FORM(xvrspic, 0x16, 0x0A, PPC2_VSX), +GEN_XX2FORM(xvrspim, 0x12, 0x0B, PPC2_VSX), +GEN_XX2FORM(xvrspip, 0x12, 0x0A, PPC2_VSX), +GEN_XX2FORM(xvrspiz, 0x12, 0x09, PPC2_VSX), + +#define VSX_LOGICAL(name, opc2, opc3, fl2) \ +GEN_XX3FORM(name, opc2, opc3, fl2) + +VSX_LOGICAL(xxland, 0x8, 0x10, PPC2_VSX), +VSX_LOGICAL(xxlandc, 0x8, 0x11, PPC2_VSX), +VSX_LOGICAL(xxlor, 0x8, 0x12, PPC2_VSX), +VSX_LOGICAL(xxlxor, 0x8, 0x13, PPC2_VSX), +VSX_LOGICAL(xxlnor, 0x8, 0x14, PPC2_VSX), +VSX_LOGICAL(xxleqv, 0x8, 0x17, PPC2_VSX207), +VSX_LOGICAL(xxlnand, 0x8, 0x16, PPC2_VSX207), +VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207), +GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX), +GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX), +GEN_XX2FORM(xxspltw, 0x08, 0x0A, PPC2_VSX), +GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00), + +#define GEN_XXSEL_ROW(opc3) \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x18, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x19, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1A, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1B, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1C, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1D, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1E, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1F, opc3, 0, PPC_NONE, PPC2_VSX), \ + +GEN_XXSEL_ROW(0x00) +GEN_XXSEL_ROW(0x01) +GEN_XXSEL_ROW(0x02) +GEN_XXSEL_ROW(0x03) +GEN_XXSEL_ROW(0x04) +GEN_XXSEL_ROW(0x05) +GEN_XXSEL_ROW(0x06) +GEN_XXSEL_ROW(0x07) +GEN_XXSEL_ROW(0x08) +GEN_XXSEL_ROW(0x09) +GEN_XXSEL_ROW(0x0A) +GEN_XXSEL_ROW(0x0B) +GEN_XXSEL_ROW(0x0C) +GEN_XXSEL_ROW(0x0D) +GEN_XXSEL_ROW(0x0E) +GEN_XXSEL_ROW(0x0F) +GEN_XXSEL_ROW(0x10) +GEN_XXSEL_ROW(0x11) +GEN_XXSEL_ROW(0x12) +GEN_XXSEL_ROW(0x13) +GEN_XXSEL_ROW(0x14) +GEN_XXSEL_ROW(0x15) +GEN_XXSEL_ROW(0x16) +GEN_XXSEL_ROW(0x17) +GEN_XXSEL_ROW(0x18) +GEN_XXSEL_ROW(0x19) +GEN_XXSEL_ROW(0x1A) +GEN_XXSEL_ROW(0x1B) +GEN_XXSEL_ROW(0x1C) +GEN_XXSEL_ROW(0x1D) +GEN_XXSEL_ROW(0x1E) +GEN_XXSEL_ROW(0x1F) + +GEN_XX3FORM_DM(xxpermdi, 0x08, 0x01), From f63fbc00d40b4a1cb1780b9abcdc019fae20ab1f Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:25 +1000 Subject: [PATCH 22/64] ppc: Rename fload_invalid_op_excp to float_invalid_op_excp No other change Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/fpu_helper.c | 122 ++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c index d9795d04d0..e1f600a810 100644 --- a/target-ppc/fpu_helper.c +++ b/target-ppc/fpu_helper.c @@ -116,7 +116,7 @@ void helper_compute_fprf(CPUPPCState *env, uint64_t arg) } /* Floating-point invalid operations exception */ -static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op, +static inline uint64_t float_invalid_op_excp(CPUPPCState *env, int op, int set_fpcc) { CPUState *cs = CPU(ppc_env_get_cpu(env)); @@ -532,12 +532,12 @@ uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2) if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); } else { if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status))) { /* sNaN addition */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status); } @@ -556,12 +556,12 @@ uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2) if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); } else { if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status))) { /* sNaN subtraction */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status); } @@ -580,12 +580,12 @@ uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2) if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); } else { if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status))) { /* sNaN multiplication */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); } @@ -604,15 +604,15 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2) if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) { /* Division of infinity by infinity */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1); } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) { /* Division of zero by zero */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1); } else { if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status))) { /* sNaN division */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); } @@ -631,14 +631,14 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ \ if (unlikely(env->fp_status.float_exception_flags)) { \ if (float64_is_any_nan(arg)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \ if (float64_is_signaling_nan(arg, &env->fp_status)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \ } \ farg.ll = nanval; \ } else if (env->fp_status.float_exception_flags & \ float_flag_invalid) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \ } \ helper_float_check_status(env); \ } \ @@ -683,7 +683,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN round */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); farg.ll = arg | 0x0008000000000000ULL; } else { int inexact = get_float_exception_flags(&env->fp_status) & @@ -735,13 +735,13 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); } else { if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status) || float64_is_signaling_nan(farg3.d, &env->fp_status))) { /* sNaN operation */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -753,7 +753,7 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); } else { ft1_128 = float64_to_float128(farg3.d, &env->fp_status); ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); @@ -778,13 +778,13 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2, (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); } else { if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status) || float64_is_signaling_nan(farg3.d, &env->fp_status))) { /* sNaN operation */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -796,7 +796,7 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2, float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); } else { ft1_128 = float64_to_float128(farg3.d, &env->fp_status); ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); @@ -819,13 +819,13 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); } else { if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status) || float64_is_signaling_nan(farg3.d, &env->fp_status))) { /* sNaN operation */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -837,7 +837,7 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); } else { ft1_128 = float64_to_float128(farg3.d, &env->fp_status); ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); @@ -864,13 +864,13 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2, (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); } else { if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status) || float64_is_signaling_nan(farg3.d, &env->fp_status))) { /* sNaN operation */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -882,7 +882,7 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2, float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); + farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); } else { ft1_128 = float64_to_float128(farg3.d, &env->fp_status); ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); @@ -905,7 +905,7 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN square root */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } f32 = float64_to_float32(farg.d, &env->fp_status); farg.d = float32_to_float64(f32, &env->fp_status); @@ -923,12 +923,12 @@ uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg) if (unlikely(float64_is_any_nan(farg.d))) { if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN reciprocal square root */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); farg.ll = float64_snan_to_qnan(farg.ll); } } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { /* Square root of a negative nonzero number */ - farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); + farg.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); } else { farg.d = float64_sqrt(farg.d, &env->fp_status); } @@ -944,7 +944,7 @@ uint64_t helper_fre(CPUPPCState *env, uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN reciprocal */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } farg.d = float64_div(float64_one, farg.d, &env->fp_status); return farg.d; @@ -960,7 +960,7 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN reciprocal */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } farg.d = float64_div(float64_one, farg.d, &env->fp_status); f32 = float64_to_float32(farg.d, &env->fp_status); @@ -979,12 +979,12 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg) if (unlikely(float64_is_any_nan(farg.d))) { if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN reciprocal square root */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); farg.ll = float64_snan_to_qnan(farg.ll); } } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { /* Reciprocal square root of a negative nonzero number */ - farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); + farg.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); } else { farg.d = float64_sqrt(farg.d, &env->fp_status); farg.d = float64_div(float64_one, farg.d, &env->fp_status); @@ -1103,7 +1103,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, && (float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status)))) { /* sNaN comparison */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } } @@ -1134,11 +1134,11 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2, if (float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status)) { /* sNaN comparison */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXVC, 1); } else { /* qNaN comparison */ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1); + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1); } } } @@ -1838,10 +1838,10 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \ } else if (tp##_is_signaling_nan(xa.fld, &tstat) || \ tp##_is_signaling_nan(xb.fld, &tstat)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ } \ } \ \ @@ -1893,10 +1893,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ if ((tp##_is_infinity(xa.fld) && tp##_is_zero(xb.fld)) || \ (tp##_is_infinity(xb.fld) && tp##_is_zero(xa.fld))) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf); \ } else if (tp##_is_signaling_nan(xa.fld, &tstat) || \ tp##_is_signaling_nan(xb.fld, &tstat)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ } \ } \ \ @@ -1944,13 +1944,13 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf); \ } else if (tp##_is_zero(xa.fld) && \ tp##_is_zero(xb.fld)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf); \ } else if (tp##_is_signaling_nan(xa.fld, &tstat) || \ tp##_is_signaling_nan(xb.fld, &tstat)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ } \ } \ \ @@ -1991,7 +1991,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ for (i = 0; i < nels; i++) { \ if (unlikely(tp##_is_signaling_nan(xb.fld, &env->fp_status))) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ } \ xt.fld = tp##_div(tp##_one, xb.fld, &env->fp_status); \ \ @@ -2038,9 +2038,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \ } else if (tp##_is_signaling_nan(xb.fld, &tstat)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ } \ } \ \ @@ -2088,9 +2088,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \ } else if (tp##_is_signaling_nan(xb.fld, &tstat)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ } \ } \ \ @@ -2277,12 +2277,12 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ if (tp##_is_signaling_nan(xa.fld, &tstat) || \ tp##_is_signaling_nan(b->fld, &tstat) || \ tp##_is_signaling_nan(c->fld, &tstat)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ tstat.float_exception_flags &= ~float_flag_invalid; \ } \ if ((tp##_is_infinity(xa.fld) && tp##_is_zero(b->fld)) || \ (tp##_is_zero(xa.fld) && tp##_is_infinity(b->fld))) { \ - xt_out.fld = float64_to_##tp(fload_invalid_op_excp(env, \ + xt_out.fld = float64_to_##tp(float_invalid_op_excp(env, \ POWERPC_EXCP_FP_VXIMZ, sfprf), &env->fp_status); \ tstat.float_exception_flags &= ~float_flag_invalid; \ } \ @@ -2290,7 +2290,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ ((tp##_is_infinity(xa.fld) || \ tp##_is_infinity(b->fld)) && \ tp##_is_infinity(c->fld))) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \ } \ } \ \ @@ -2360,10 +2360,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ float64_is_any_nan(xb.VsrD(0)))) { \ if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) || \ float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ } \ if (ordered) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ } \ cc = 1; \ } else { \ @@ -2408,7 +2408,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ xt.fld = tp##_##op(xa.fld, xb.fld, &env->fp_status); \ if (unlikely(tp##_is_signaling_nan(xa.fld, &env->fp_status) || \ tp##_is_signaling_nan(xb.fld, &env->fp_status))) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ } \ } \ \ @@ -2448,10 +2448,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ tp##_is_any_nan(xb.fld))) { \ if (tp##_is_signaling_nan(xa.fld, &env->fp_status) || \ tp##_is_signaling_nan(xb.fld, &env->fp_status)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ } \ if (svxvc) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ } \ xt.fld = 0; \ all_true = 0; \ @@ -2502,7 +2502,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \ if (unlikely(stp##_is_signaling_nan(xb.sfld, \ &env->fp_status))) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ xt.tfld = ttp##_snan_to_qnan(xt.tfld); \ } \ if (sfprf) { \ @@ -2557,15 +2557,15 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ for (i = 0; i < nels; i++) { \ if (unlikely(stp##_is_any_nan(xb.sfld))) { \ if (stp##_is_signaling_nan(xb.sfld, &env->fp_status)) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ } \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ xt.tfld = rnan; \ } else { \ xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, \ &env->fp_status); \ if (env->fp_status.float_exception_flags & float_flag_invalid) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ } \ } \ } \ @@ -2667,7 +2667,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ for (i = 0; i < nels; i++) { \ if (unlikely(tp##_is_signaling_nan(xb.fld, \ &env->fp_status))) { \ - fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ xt.fld = tp##_snan_to_qnan(xb.fld); \ } else { \ xt.fld = tp##_round_to_int(xb.fld, &env->fp_status); \ From a93ecff935af312d49e4c9349b6527813af303f5 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:26 +1000 Subject: [PATCH 23/64] ppc: Make float_invalid_op_excp() pass the return address Instead of relying on NIP having been updated already Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/fpu_helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c index e1f600a810..8d881fccfd 100644 --- a/target-ppc/fpu_helper.c +++ b/target-ppc/fpu_helper.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" +#include "exec/exec-all.h" #define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL) #define float32_snan_to_qnan(x) ((x) | 0x00400000) @@ -200,8 +201,9 @@ static inline uint64_t float_invalid_op_excp(CPUPPCState *env, int op, /* Update the floating-point enabled exception summary */ env->fpscr |= 1 << FPSCR_FEX; if (msr_fe0 != 0 || msr_fe1 != 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_FP | op); + /* GETPC() works here because this is inline */ + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_FP | op, GETPC()); } } return ret; From 44f35bd1ac3dccd4e7fbd5d443c84e959c8a1a14 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:27 +1000 Subject: [PATCH 24/64] ppc: Make float_check_status() pass the return address Instead of relying on NIP having been updated already. Signed-off-by: Benjamin Herrenschmidt [dwg: Fold in fix to mark function always_inline] Signed-off-by: David Gibson --- target-ppc/fpu_helper.c | 67 ++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c index 8d881fccfd..b0760f041d 100644 --- a/target-ppc/fpu_helper.c +++ b/target-ppc/fpu_helper.c @@ -117,8 +117,8 @@ void helper_compute_fprf(CPUPPCState *env, uint64_t arg) } /* Floating-point invalid operations exception */ -static inline uint64_t float_invalid_op_excp(CPUPPCState *env, int op, - int set_fpcc) +static inline __attribute__((__always_inline__)) +uint64_t float_invalid_op_excp(CPUPPCState *env, int op, int set_fpcc) { CPUState *cs = CPU(ppc_env_get_cpu(env)); uint64_t ret = 0; @@ -209,7 +209,7 @@ static inline uint64_t float_invalid_op_excp(CPUPPCState *env, int op, return ret; } -static inline void float_zero_divide_excp(CPUPPCState *env) +static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) { env->fpscr |= 1 << FPSCR_ZX; env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); @@ -219,8 +219,9 @@ static inline void float_zero_divide_excp(CPUPPCState *env) /* Update the floating-point enabled exception summary */ env->fpscr |= 1 << FPSCR_FEX; if (msr_fe0 != 0 || msr_fe1 != 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX, + raddr); } } } @@ -493,13 +494,13 @@ void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) helper_store_fpscr(env, arg, mask); } -void helper_float_check_status(CPUPPCState *env) +static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) { CPUState *cs = CPU(ppc_env_get_cpu(env)); int status = get_float_exception_flags(&env->fp_status); if (status & float_flag_divbyzero) { - float_zero_divide_excp(env); + float_zero_divide_excp(env, raddr); } else if (status & float_flag_overflow) { float_overflow_excp(env); } else if (status & float_flag_underflow) { @@ -512,12 +513,24 @@ void helper_float_check_status(CPUPPCState *env) (env->error_code & POWERPC_EXCP_FP)) { /* Differred floating-point exception after target FPR update */ if (msr_fe0 != 0 || msr_fe1 != 0) { - helper_raise_exception_err(env, cs->exception_index, - env->error_code); + raise_exception_err_ra(env, cs->exception_index, + env->error_code, raddr); } } } +static inline __attribute__((__always_inline__)) +void float_check_status(CPUPPCState *env) +{ + /* GETPC() works here because this is inline */ + do_float_check_status(env, GETPC()); +} + +void helper_float_check_status(CPUPPCState *env) +{ + do_float_check_status(env, GETPC()); +} + void helper_reset_fpstatus(CPUPPCState *env) { set_float_exception_flags(0, &env->fp_status); @@ -642,7 +655,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ float_flag_invalid) { \ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \ } \ - helper_float_check_status(env); \ + float_check_status(env); \ } \ return farg.ll; \ } @@ -667,7 +680,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ } else { \ farg.d = cvtr(arg, &env->fp_status); \ } \ - helper_float_check_status(env); \ + float_check_status(env); \ return farg.ll; \ } @@ -700,7 +713,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, env->fp_status.float_exception_flags &= ~float_flag_inexact; } } - helper_float_check_status(env); + float_check_status(env); return farg.ll; } @@ -1856,7 +1869,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ } \ } \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0) @@ -1912,7 +1925,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0) @@ -1966,7 +1979,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0) @@ -2007,7 +2020,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0) @@ -2056,7 +2069,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0) @@ -2106,7 +2119,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0) @@ -2305,7 +2318,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ } \ putVSR(xT(opcode), &xt_out, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } #define MADD_FLGS 0 @@ -2383,7 +2396,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ env->fpscr |= cc << FPSCR_FPRF; \ env->crf[BF(opcode)] = cc; \ \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_SCALAR_CMP(xscmpodp, 1) @@ -2415,7 +2428,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0)) @@ -2472,7 +2485,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ if ((opcode >> (31-21)) & 1) { \ env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \ } \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0) @@ -2514,7 +2527,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1) @@ -2573,7 +2586,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \ @@ -2624,7 +2637,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0) @@ -2688,7 +2701,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + float_check_status(env); \ } VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1) @@ -2716,6 +2729,6 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb) uint64_t xt = helper_frsp(env, xb); helper_compute_fprf(env, xt); - helper_float_check_status(env); + float_check_status(env); return xt; } From ef24726e4847d61ca647e3ae8dc47422ca721259 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:28 +1000 Subject: [PATCH 25/64] ppc: Don't update the NIP in floating point generated code This is no longer necessary as the helpers will properly retrieve the return address. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate/fp-impl.c | 28 ---------------------------- target-ppc/translate/vsx-impl.c | 6 ------ 2 files changed, 34 deletions(-) diff --git a/target-ppc/translate/fp-impl.c b/target-ppc/translate/fp-impl.c index 2abc386fcc..9ba9289157 100644 --- a/target-ppc/translate/fp-impl.c +++ b/target-ppc/translate/fp-impl.c @@ -38,8 +38,6 @@ static void gen_f##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ gen_reset_fpstatus(); \ gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ cpu_fpr[rA(ctx->opcode)], \ @@ -67,8 +65,6 @@ static void gen_f##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ gen_reset_fpstatus(); \ gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ cpu_fpr[rA(ctx->opcode)], \ @@ -95,8 +91,6 @@ static void gen_f##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ gen_reset_fpstatus(); \ gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ cpu_fpr[rA(ctx->opcode)], \ @@ -123,8 +117,6 @@ static void gen_f##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ gen_reset_fpstatus(); \ gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ cpu_fpr[rB(ctx->opcode)]); \ @@ -143,8 +135,6 @@ static void gen_f##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ gen_reset_fpstatus(); \ gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ cpu_fpr[rB(ctx->opcode)]); \ @@ -179,8 +169,6 @@ static void gen_frsqrtes(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_FPU); return; } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env, cpu_fpr[rB(ctx->opcode)]); @@ -205,8 +193,6 @@ static void gen_fsqrt(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_FPU); return; } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env, cpu_fpr[rB(ctx->opcode)]); @@ -222,8 +208,6 @@ static void gen_fsqrts(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_FPU); return; } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env, cpu_fpr[rB(ctx->opcode)]); @@ -313,8 +297,6 @@ static void gen_fcmpo(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_FPU); return; } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); crf = tcg_const_i32(crfD(ctx->opcode)); gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)], @@ -331,8 +313,6 @@ static void gen_fcmpu(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_FPU); return; } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); crf = tcg_const_i32(crfD(ctx->opcode)); gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)], @@ -502,8 +482,6 @@ static void gen_mtfsb0(DisasContext *ctx) gen_reset_fpstatus(); if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) { TCGv_i32 t0; - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_const_i32(crb); gen_helper_fpscr_clrbit(cpu_env, t0); tcg_temp_free_i32(t0); @@ -528,8 +506,6 @@ static void gen_mtfsb1(DisasContext *ctx) /* XXX: we pretend we can only do IEEE floating-point computations */ if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) { TCGv_i32 t0; - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_const_i32(crb); gen_helper_fpscr_setbit(cpu_env, t0); tcg_temp_free_i32(t0); @@ -559,8 +535,6 @@ static void gen_mtfsf(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); return; } - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); if (l) { t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff); @@ -595,8 +569,6 @@ static void gen_mtfsfi(DisasContext *ctx) return; } sh = (8 * w) + 7 - bf; - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh)); t1 = tcg_const_i32(1 << sh); diff --git a/target-ppc/translate/vsx-impl.c b/target-ppc/translate/vsx-impl.c index 7361c4779c..9f77b06bd8 100644 --- a/target-ppc/translate/vsx-impl.c +++ b/target-ppc/translate/vsx-impl.c @@ -380,8 +380,6 @@ static void gen_##name(DisasContext * ctx) \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ - /* NIP cannot be restored if the memory exception comes from an helper */ \ - gen_update_nip(ctx, ctx->nip - 4); \ opc = tcg_const_i32(ctx->opcode); \ gen_helper_##name(cpu_env, opc); \ tcg_temp_free_i32(opc); \ @@ -394,10 +392,6 @@ static void gen_##name(DisasContext * ctx) \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ - /* NIP cannot be restored if the exception comes */ \ - /* from a helper. */ \ - gen_update_nip(ctx, ctx->nip - 4); \ - \ gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env, \ cpu_vsrh(xB(ctx->opcode))); \ } From 1b7d17cae4c31e7cf16abd7036f5a5ca5dee8c57 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:29 +1000 Subject: [PATCH 26/64] ppc: FP exceptions are always precise We don't implement imprecise FP exceptions and using store_current which sets SRR1 to the *previous* instruction never makes sense for these. So let's be truthful and make them precise, which is allowed by the architecture. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/excp_helper.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 96c6fd9eb0..02d9e79e79 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -274,12 +274,13 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) env->error_code = 0; return; } + + /* FP exceptions always have NIP pointing to the faulting + * instruction, so always use store_next and claim we are + * precise in the MSR. + */ msr |= 0x00100000; - if (msr_fe0 == msr_fe1) { - goto store_next; - } - msr |= 0x00010000; - break; + goto store_next; case POWERPC_EXCP_INVAL: LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); msr |= 0x00080000; From e41029b378b4a65a0b89b5a8dc087aca6b5d012d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:30 +1000 Subject: [PATCH 27/64] ppc: Don't update NIP in lswi/lswx/stswi/stswx Instead, pass GETPC() result to the corresponding helpers. This requires a bit of fiddling to get the PC (hopefully) right in the case where we generate a program check, though the hacks there are temporary, a subsequent patch will clean this all up by always having the nip already set to the right instruction when taking the fault. Signed-off-by: Benjamin Herrenschmidt [dwg: Fix trivial checkpatch warning] Signed-off-by: David Gibson --- target-ppc/excp_helper.c | 8 ++++++++ target-ppc/mem_helper.c | 26 ++++++++++++++++---------- target-ppc/translate.c | 18 ++++++++---------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 02d9e79e79..6aa03295e0 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -285,6 +285,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); msr |= 0x00080000; env->spr[SPR_BOOKE_ESR] = ESR_PIL; + /* Some invalids will have the PC in the right place already */ + if (env->error_code & POWERPC_EXCP_INVAL_LSWX) { + goto store_next; + } break; case POWERPC_EXCP_PRIV: msr |= 0x00040000; @@ -306,6 +310,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) srr1 = SPR_HSRR1; new_msr |= (target_ulong)MSR_HVB; new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + /* Some invalids will have the PC in the right place already */ + if (env->error_code == (POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX)) { + goto store_next; + } goto store_current; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ goto store_current; diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index e4ed3773e8..de96c91e40 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -77,23 +77,30 @@ void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg) } } -void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg) +static void do_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, + uint32_t reg, uintptr_t raddr) { int sh; for (; nb > 3; nb -= 4) { - env->gpr[reg] = cpu_ldl_data(env, addr); + env->gpr[reg] = cpu_ldl_data_ra(env, addr, raddr); reg = (reg + 1) % 32; addr = addr_add(env, addr, 4); } if (unlikely(nb > 0)) { env->gpr[reg] = 0; for (sh = 24; nb > 0; nb--, sh -= 8) { - env->gpr[reg] |= cpu_ldub_data(env, addr) << sh; + env->gpr[reg] |= cpu_ldub_data_ra(env, addr, raddr) << sh; addr = addr_add(env, addr, 1); } } } + +void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg) +{ + do_lsw(env, addr, nb, reg, GETPC()); +} + /* PPC32 specification says we must generate an exception if * rA is in the range of registers to be loaded. * In an other hand, IBM says this is valid, but rA won't be loaded. @@ -106,12 +113,11 @@ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg, int num_used_regs = (xer_bc + 3) / 4; if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) || lsw_reg_in_range(reg, num_used_regs, rb))) { - env->nip += 4; /* Compensate the "nip - 4" from gen_lswx() */ - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | - POWERPC_EXCP_INVAL_LSWX); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_LSWX, GETPC()); } else { - helper_lsw(env, addr, xer_bc, reg); + do_lsw(env, addr, xer_bc, reg, GETPC()); } } } @@ -122,13 +128,13 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb, int sh; for (; nb > 3; nb -= 4) { - cpu_stl_data(env, addr, env->gpr[reg]); + cpu_stl_data_ra(env, addr, env->gpr[reg], GETPC()); reg = (reg + 1) % 32; addr = addr_add(env, addr, 4); } if (unlikely(nb > 0)) { for (sh = 24; nb > 0; nb--, sh -= 8) { - cpu_stb_data(env, addr, (env->gpr[reg] >> sh) & 0xFF); + cpu_stb_data_ra(env, addr, (env->gpr[reg] >> sh) & 0xFF, GETPC()); addr = addr_add(env, addr, 1); } } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index a327072e06..568c1f833d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2916,12 +2916,16 @@ static void gen_lswi(DisasContext *ctx) nb = 32; nr = (nb + 3) / 4; if (unlikely(lsw_reg_in_range(start, nr, ra))) { + /* The handler expects the PC to point to *this* instruction, + * so setting ctx->exception here prevents it from being + * improperly updated again by gen_inval_exception + */ + gen_update_nip(ctx, ctx->nip - 4); + ctx->exception = POWERPC_EXCP_HV_EMU; gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX); return; } gen_set_access_type(ctx, ACCESS_INT); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_temp_new(); gen_addr_register(ctx, t0); t1 = tcg_const_i32(nb); @@ -2938,8 +2942,6 @@ static void gen_lswx(DisasContext *ctx) TCGv t0; TCGv_i32 t1, t2, t3; gen_set_access_type(ctx, ACCESS_INT); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); t1 = tcg_const_i32(rD(ctx->opcode)); @@ -2959,8 +2961,6 @@ static void gen_stswi(DisasContext *ctx) TCGv_i32 t1, t2; int nb = NB(ctx->opcode); gen_set_access_type(ctx, ACCESS_INT); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_temp_new(); gen_addr_register(ctx, t0); if (nb == 0) @@ -2979,8 +2979,6 @@ static void gen_stswx(DisasContext *ctx) TCGv t0; TCGv_i32 t1, t2; gen_set_access_type(ctx, ACCESS_INT); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); t1 = tcg_temp_new_i32(); @@ -4083,7 +4081,7 @@ static void gen_dcbz(DisasContext *ctx) static void gen_dst(DisasContext *ctx) { if (rA(ctx->opcode) == 0) { - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX); + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); } else { /* interpreted as no-op */ } @@ -4093,7 +4091,7 @@ static void gen_dst(DisasContext *ctx) static void gen_dstst(DisasContext *ctx) { if (rA(ctx->opcode) == 0) { - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX); + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); } else { /* interpreted as no-op */ } From af6d376ea18db87287a9e0de08fe23c68f2464a6 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:31 +1000 Subject: [PATCH 28/64] ppc: Don't update NIP in lmw/stmw/icbi Instead, pass GETPC() result to the corresponding helpers. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/mem_helper.c | 11 ++++++----- target-ppc/translate.c | 6 ------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index de96c91e40..e20a53eb50 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -57,9 +57,9 @@ void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg) { for (; reg < 32; reg++) { if (needs_byteswap(env)) { - env->gpr[reg] = bswap32(cpu_ldl_data(env, addr)); + env->gpr[reg] = bswap32(cpu_ldl_data_ra(env, addr, GETPC())); } else { - env->gpr[reg] = cpu_ldl_data(env, addr); + env->gpr[reg] = cpu_ldl_data_ra(env, addr, GETPC()); } addr = addr_add(env, addr, 4); } @@ -69,9 +69,10 @@ void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg) { for (; reg < 32; reg++) { if (needs_byteswap(env)) { - cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg])); + cpu_stl_data_ra(env, addr, bswap32((uint32_t)env->gpr[reg]), + GETPC()); } else { - cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]); + cpu_stl_data_ra(env, addr, (uint32_t)env->gpr[reg], GETPC()); } addr = addr_add(env, addr, 4); } @@ -178,7 +179,7 @@ void helper_icbi(CPUPPCState *env, target_ulong addr) * (not a fetch) by the MMU. To be sure it will be so, * do the load "by hand". */ - cpu_ldl_data(env, addr); + cpu_ldl_data_ra(env, addr, GETPC()); } /* XXX: to be tested */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 568c1f833d..dc5ebb180d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2869,8 +2869,6 @@ static void gen_lmw(DisasContext *ctx) TCGv t0; TCGv_i32 t1; gen_set_access_type(ctx, ACCESS_INT); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_temp_new(); t1 = tcg_const_i32(rD(ctx->opcode)); gen_addr_imm_index(ctx, t0, 0); @@ -2885,8 +2883,6 @@ static void gen_stmw(DisasContext *ctx) TCGv t0; TCGv_i32 t1; gen_set_access_type(ctx, ACCESS_INT); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_temp_new(); t1 = tcg_const_i32(rS(ctx->opcode)); gen_addr_imm_index(ctx, t0, 0); @@ -4109,8 +4105,6 @@ static void gen_icbi(DisasContext *ctx) { TCGv t0; gen_set_access_type(ctx, ACCESS_CACHE); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_icbi(cpu_env, t0); From bd6fefe71cec5a0c7d2be4ac96307f25db56abf9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:32 +1000 Subject: [PATCH 29/64] ppc: Make tlb_fill() use new exception helper Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- linux-user/main.c | 12 ++-- target-ppc/excp_helper.c | 146 +++++++++++++++------------------------ target-ppc/mmu_helper.c | 7 +- target-ppc/translate.c | 60 +++++++++------- 4 files changed, 97 insertions(+), 128 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index f2f4d2f05a..d112834644 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1814,7 +1814,7 @@ void cpu_loop(CPUPPCState *env) env->error_code); break; } - info._sifields._sigfault._addr = env->nip - 4; + info._sifields._sigfault._addr = env->nip; queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ @@ -1822,7 +1822,7 @@ void cpu_loop(CPUPPCState *env) info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; - info._sifields._sigfault._addr = env->nip - 4; + info._sifields._sigfault._addr = env->nip; queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_SYSCALL: /* System call exception */ @@ -1834,7 +1834,7 @@ void cpu_loop(CPUPPCState *env) info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; - info._sifields._sigfault._addr = env->nip - 4; + info._sifields._sigfault._addr = env->nip; queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_DECR: /* Decrementer exception */ @@ -1862,7 +1862,7 @@ void cpu_loop(CPUPPCState *env) info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; - info._sifields._sigfault._addr = env->nip - 4; + info._sifields._sigfault._addr = env->nip; queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */ @@ -1926,7 +1926,7 @@ void cpu_loop(CPUPPCState *env) info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; - info._sifields._sigfault._addr = env->nip - 4; + info._sifields._sigfault._addr = env->nip; queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */ @@ -2001,9 +2001,9 @@ void cpu_loop(CPUPPCState *env) env->gpr[5], env->gpr[6], env->gpr[7], env->gpr[8], 0, 0); if (ret == -TARGET_ERESTARTSYS) { - env->nip -= 4; break; } + env->nip += 4; if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) { /* Returning from a successful sigreturn syscall. Avoid corrupting register state. */ diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 6aa03295e0..d31eece4dd 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -198,7 +198,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) default: goto excp_invalid; } - goto store_next; + break; case POWERPC_EXCP_MCHECK: /* Machine check exception */ if (msr_me == 0) { /* Machine check exception is not enabled. @@ -235,16 +235,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) default: break; } - goto store_next; + break; case POWERPC_EXCP_DSI: /* Data storage exception */ LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); - goto store_next; + break; case POWERPC_EXCP_ISI: /* Instruction storage exception */ LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx "\n", msr, env->nip); msr |= env->error_code; - goto store_next; + break; case POWERPC_EXCP_EXTERNAL: /* External input */ cs = CPU(cpu); @@ -258,13 +258,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) /* IACK the IRQ on delivery */ env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack); } - goto store_next; + break; case POWERPC_EXCP_ALIGN: /* Alignment exception */ /* XXX: this is false */ /* Get rS/rD and rA from faulting opcode */ - env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4)) + /* Broken for LE mode */ + env->spr[SPR_DSISR] |= (cpu_ldl_code(env, env->nip) & 0x03FF0000) >> 16; - goto store_next; + break; case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: @@ -280,15 +281,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) * precise in the MSR. */ msr |= 0x00100000; - goto store_next; + break; case POWERPC_EXCP_INVAL: LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); msr |= 0x00080000; env->spr[SPR_BOOKE_ESR] = ESR_PIL; - /* Some invalids will have the PC in the right place already */ - if (env->error_code & POWERPC_EXCP_INVAL_LSWX) { - goto store_next; - } break; case POWERPC_EXCP_PRIV: msr |= 0x00040000; @@ -304,23 +301,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) env->error_code); break; } - goto store_current; - case POWERPC_EXCP_HV_EMU: - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - /* Some invalids will have the PC in the right place already */ - if (env->error_code == (POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX)) { - goto store_next; - } - goto store_current; - case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ - goto store_current; + break; case POWERPC_EXCP_SYSCALL: /* System call exception */ dump_syscall(env); lev = env->error_code; + /* We need to correct the NIP which in this case is supposed + * to point to the next instruction + */ + env->nip += 4; + /* "PAPR mode" built-in hypercall emulation */ if ((lev == 1) && cpu_ppc_hypercall) { cpu_ppc_hypercall(cpu); @@ -329,15 +319,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) if (lev == 1) { new_msr |= (target_ulong)MSR_HVB; } - goto store_next; + break; + case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ - goto store_current; case POWERPC_EXCP_DECR: /* Decrementer exception */ - goto store_next; + break; case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ /* FIT on 4xx */ LOG_EXCP("FIT exception\n"); - goto store_next; + break; case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ LOG_EXCP("WDT exception\n"); switch (excp_model) { @@ -348,11 +338,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) default: break; } - goto store_next; + break; case POWERPC_EXCP_DTLB: /* Data TLB error */ - goto store_next; case POWERPC_EXCP_ITLB: /* Instruction TLB error */ - goto store_next; + break; case POWERPC_EXCP_DEBUG: /* Debug interrupt */ switch (excp_model) { case POWERPC_EXCP_BOOKE: @@ -367,33 +356,33 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } /* XXX: TODO */ cpu_abort(cs, "Debug exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ env->spr[SPR_BOOKE_ESR] = ESR_SPV; - goto store_current; + break; case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ /* XXX: TODO */ cpu_abort(cs, "Embedded floating point data exception " "is not implemented yet !\n"); env->spr[SPR_BOOKE_ESR] = ESR_SPV; - goto store_next; + break; case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ /* XXX: TODO */ cpu_abort(cs, "Embedded floating point round exception " "is not implemented yet !\n"); env->spr[SPR_BOOKE_ESR] = ESR_SPV; - goto store_next; + break; case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ /* XXX: TODO */ cpu_abort(cs, "Performance counter exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ - goto store_next; + break; case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ srr0 = SPR_BOOKE_CSRR0; srr1 = SPR_BOOKE_CSRR1; - goto store_next; + break; case POWERPC_EXCP_RESET: /* System reset exception */ if (msr_pow) { /* indicate that we resumed from power save mode */ @@ -404,65 +393,42 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) new_msr |= (target_ulong)MSR_HVB; ail = 0; - goto store_next; + break; case POWERPC_EXCP_DSEG: /* Data segment exception */ - goto store_next; case POWERPC_EXCP_ISEG: /* Instruction segment exception */ - goto store_next; - case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; case POWERPC_EXCP_TRACE: /* Trace exception */ - goto store_next; + break; + case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ + case POWERPC_EXCP_HV_EMU: srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; new_msr |= (target_ulong)MSR_HVB; new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; + break; case POWERPC_EXCP_VPU: /* Vector unavailable exception */ - goto store_current; case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ - goto store_current; case POWERPC_EXCP_FU: /* Facility unavailable exception */ - goto store_current; + break; case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ LOG_EXCP("PIT exception\n"); - goto store_next; + break; case POWERPC_EXCP_IO: /* IO error exception */ /* XXX: TODO */ cpu_abort(cs, "601 IO error exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_RUNM: /* Run mode exception */ /* XXX: TODO */ cpu_abort(cs, "601 run mode exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_EMUL: /* Emulation trap exception */ /* XXX: TODO */ cpu_abort(cs, "602 emulation trap exception " "is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ switch (excp_model) { case POWERPC_EXCP_602: @@ -577,71 +543,67 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) cpu_abort(cs, "Invalid data store TLB miss exception\n"); break; } - goto store_next; + break; case POWERPC_EXCP_FPA: /* Floating-point assist exception */ /* XXX: TODO */ cpu_abort(cs, "Floating point assist exception " "is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_DABR: /* Data address breakpoint */ /* XXX: TODO */ cpu_abort(cs, "DABR exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ /* XXX: TODO */ cpu_abort(cs, "IABR exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_SMI: /* System management interrupt */ /* XXX: TODO */ cpu_abort(cs, "SMI exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_THERM: /* Thermal interrupt */ /* XXX: TODO */ cpu_abort(cs, "Thermal management exception " "is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ /* XXX: TODO */ cpu_abort(cs, "Performance counter exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_VPUA: /* Vector assist exception */ /* XXX: TODO */ cpu_abort(cs, "VPU assist exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_SOFTP: /* Soft patch exception */ /* XXX: TODO */ cpu_abort(cs, "970 soft-patch exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_MAINT: /* Maintenance exception */ /* XXX: TODO */ cpu_abort(cs, "970 maintenance exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ /* XXX: TODO */ cpu_abort(cs, "Maskable external exception " "is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ /* XXX: TODO */ cpu_abort(cs, "Non maskable external exception " "is not implemented yet !\n"); - goto store_next; + break; default: excp_invalid: cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); break; - store_current: - /* save current instruction location */ - env->spr[srr0] = env->nip - 4; - break; - store_next: - /* save next instruction location */ - env->spr[srr0] = env->nip; - break; } + + /* Save PC */ + env->spr[srr0] = env->nip; + /* Save MSR */ env->spr[srr1] = msr; diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 737f338fb9..692398c3f0 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -2892,10 +2892,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, ret = cpu_ppc_handle_mmu_fault(env, addr, access_type, mmu_idx); } if (unlikely(ret != 0)) { - if (likely(retaddr)) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } - helper_raise_exception_err(env, cs->exception_index, env->error_code); + raise_exception_err_ra(env, cs->exception_index, env->error_code, + retaddr); } } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index dc5ebb180d..afcdd3e12a 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -276,8 +276,12 @@ void gen_update_current_nip(void *opaque) static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error) { TCGv_i32 t0, t1; + + /* These are all synchronous exceptions, we set the PC back to + * the faulting instruction + */ if (ctx->exception == POWERPC_EXCP_NONE) { - gen_update_nip(ctx, ctx->nip); + gen_update_nip(ctx, ctx->nip - 4); } t0 = tcg_const_i32(excp); t1 = tcg_const_i32(error); @@ -290,8 +294,12 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error) static void gen_exception(DisasContext *ctx, uint32_t excp) { TCGv_i32 t0; + + /* These are all synchronous exceptions, we set the PC back to + * the faulting instruction + */ if (ctx->exception == POWERPC_EXCP_NONE) { - gen_update_nip(ctx, ctx->nip); + gen_update_nip(ctx, ctx->nip - 4); } t0 = tcg_const_i32(excp); gen_helper_raise_exception(cpu_env, t0); @@ -299,13 +307,28 @@ static void gen_exception(DisasContext *ctx, uint32_t excp) ctx->exception = (excp); } +static void gen_exception_nip(DisasContext *ctx, uint32_t excp, + target_ulong nip) +{ + TCGv_i32 t0; + + gen_update_nip(ctx, nip); + t0 = tcg_const_i32(excp); + gen_helper_raise_exception(cpu_env, t0); + tcg_temp_free_i32(t0); + ctx->exception = (excp); +} + static void gen_debug_exception(DisasContext *ctx) { TCGv_i32 t0; + /* These are all synchronous exceptions, we set the PC back to + * the faulting instruction + */ if ((ctx->exception != POWERPC_EXCP_BRANCH) && (ctx->exception != POWERPC_EXCP_SYNC)) { - gen_update_nip(ctx, ctx->nip); + gen_update_nip(ctx, ctx->nip - 4); } t0 = tcg_const_i32(EXCP_DEBUG); gen_helper_raise_exception(cpu_env, t0); @@ -1643,7 +1666,7 @@ static void gen_pause(DisasContext *ctx) tcg_temp_free_i32(t0); /* Stop translation, this gives other CPUs a chance to run */ - gen_exception_err(ctx, EXCP_HLT, 1); + gen_exception_nip(ctx, EXCP_HLT, ctx->nip); } #endif /* defined(TARGET_PPC64) */ @@ -2912,12 +2935,6 @@ static void gen_lswi(DisasContext *ctx) nb = 32; nr = (nb + 3) / 4; if (unlikely(lsw_reg_in_range(start, nr, ra))) { - /* The handler expects the PC to point to *this* instruction, - * so setting ctx->exception here prevents it from being - * improperly updated again by gen_inval_exception - */ - gen_update_nip(ctx, ctx->nip - 4); - ctx->exception = POWERPC_EXCP_HV_EMU; gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX); return; } @@ -3055,16 +3072,12 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA, int reg, int size) { TCGv t0 = tcg_temp_new(); - uint32_t save_exception = ctx->exception; tcg_gen_st_tl(EA, cpu_env, offsetof(CPUPPCState, reserve_ea)); tcg_gen_movi_tl(t0, (size << 5) | reg); tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, reserve_info)); tcg_temp_free(t0); - gen_update_nip(ctx, ctx->nip-4); - ctx->exception = POWERPC_EXCP_BRANCH; - gen_exception(ctx, POWERPC_EXCP_STCX); - ctx->exception = save_exception; + gen_exception_err(ctx, POWERPC_EXCP_STCX, 0); } #else static void gen_conditional_store(DisasContext *ctx, TCGv EA, @@ -3203,7 +3216,7 @@ static void gen_wait(DisasContext *ctx) -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted)); tcg_temp_free_i32(t0); /* Stop translation, as the CPU is supposed to sleep from now */ - gen_exception_err(ctx, EXCP_HLT, 1); + gen_exception_nip(ctx, EXCP_HLT, ctx->nip); } #if defined(TARGET_PPC64) @@ -3306,10 +3319,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) && (ctx->exception == POWERPC_EXCP_BRANCH || ctx->exception == POWERPC_EXCP_TRACE)) { - target_ulong tmp = ctx->nip; - ctx->nip = dest; - gen_exception(ctx, POWERPC_EXCP_TRACE); - ctx->nip = tmp; + gen_exception_nip(ctx, POWERPC_EXCP_TRACE, dest); } if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) { gen_debug_exception(ctx); @@ -3578,7 +3588,7 @@ static void gen_tw(DisasContext *ctx) { TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode)); /* Update the nip since this might generate a trap exception */ - gen_update_nip(ctx, ctx->nip); + gen_update_nip(ctx, ctx->nip - 4); gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); tcg_temp_free_i32(t0); @@ -3590,7 +3600,7 @@ static void gen_twi(DisasContext *ctx) TCGv t0 = tcg_const_tl(SIMM(ctx->opcode)); TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode)); /* Update the nip since this might generate a trap exception */ - gen_update_nip(ctx, ctx->nip); + gen_update_nip(ctx, ctx->nip - 4); gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free_i32(t1); @@ -3602,7 +3612,7 @@ static void gen_td(DisasContext *ctx) { TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode)); /* Update the nip since this might generate a trap exception */ - gen_update_nip(ctx, ctx->nip); + gen_update_nip(ctx, ctx->nip - 4); gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); tcg_temp_free_i32(t0); @@ -3614,7 +3624,7 @@ static void gen_tdi(DisasContext *ctx) TCGv t0 = tcg_const_tl(SIMM(ctx->opcode)); TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode)); /* Update the nip since this might generate a trap exception */ - gen_update_nip(ctx, ctx->nip); + gen_update_nip(ctx, ctx->nip - 4); gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free_i32(t1); @@ -7054,7 +7064,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.exception != POWERPC_SYSCALL && ctx.exception != POWERPC_EXCP_TRAP && ctx.exception != POWERPC_EXCP_BRANCH)) { - gen_exception(ctxp, POWERPC_EXCP_TRACE); + gen_exception_nip(ctxp, POWERPC_EXCP_TRACE, ctx.nip); } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || (cs->singlestep_enabled) || singlestep || From 0f72b7c682811fc3281e3b5f4d467582550c6a51 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:34 +1000 Subject: [PATCH 30/64] ppc: Fix source NIP on SLB related interrupts We need to pass it to the raise helper since we don't update it before the calls. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/mmu-hash64.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index 5de1358d1c..8118143874 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -241,8 +241,8 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) PowerPCCPU *cpu = ppc_env_get_cpu(env); if (ppc_store_slb(cpu, rb & 0xfff, rb & ~0xfffULL, rs) < 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL, GETPC()); } } @@ -252,8 +252,8 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb) target_ulong rt = 0; if (ppc_load_slb_esid(cpu, rb, &rt) < 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL, GETPC()); } return rt; } @@ -264,8 +264,8 @@ target_ulong helper_find_slb_vsid(CPUPPCState *env, target_ulong rb) target_ulong rt = 0; if (ppc_find_slb_vsid(cpu, rb, &rt) < 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL, GETPC()); } return rt; } @@ -276,8 +276,8 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb) target_ulong rt = 0; if (ppc_load_slb_vsid(cpu, rb, &rt) < 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL, GETPC()); } return rt; } From a13f0a9bc4e6f35be3f64bd7048eec565957a7d4 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:35 +1000 Subject: [PATCH 31/64] ppc: Don't update NIP in DCR access routines This is no longer necessary as the helpers will properly retrieve the return address when needed Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/timebase_helper.c | 23 +++++++++++++---------- target-ppc/translate.c | 12 ------------ 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c index a07faa42cb..73363e08ae 100644 --- a/target-ppc/timebase_helper.c +++ b/target-ppc/timebase_helper.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" +#include "exec/exec-all.h" #include "qemu/log.h" /*****************************************************************************/ @@ -143,15 +144,16 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn) if (unlikely(env->dcr_env == NULL)) { qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n"); - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | - POWERPC_EXCP_INVAL_INVAL); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL, GETPC()); } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) { qemu_log_mask(LOG_GUEST_ERROR, "DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn); - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_PRIV_REG, GETPC()); } return val; } @@ -160,14 +162,15 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, target_ulong val) { if (unlikely(env->dcr_env == NULL)) { qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n"); - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | - POWERPC_EXCP_INVAL_INVAL); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL, GETPC()); } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) { qemu_log_mask(LOG_GUEST_ERROR, "DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn); - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_PRIV_REG, GETPC()); } } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index afcdd3e12a..46b0e188c2 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -5498,8 +5498,6 @@ static void gen_mfdcr(DisasContext *ctx) TCGv dcrn; CHK_SV; - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); dcrn = tcg_const_tl(SPR(ctx->opcode)); gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, dcrn); tcg_temp_free(dcrn); @@ -5515,8 +5513,6 @@ static void gen_mtdcr(DisasContext *ctx) TCGv dcrn; CHK_SV; - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); dcrn = tcg_const_tl(SPR(ctx->opcode)); gen_helper_store_dcr(cpu_env, dcrn, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(dcrn); @@ -5531,8 +5527,6 @@ static void gen_mfdcrx(DisasContext *ctx) GEN_PRIV; #else CHK_SV; - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ @@ -5547,8 +5541,6 @@ static void gen_mtdcrx(DisasContext *ctx) GEN_PRIV; #else CHK_SV; - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ @@ -5558,8 +5550,6 @@ static void gen_mtdcrx(DisasContext *ctx) /* mfdcrux (PPC 460) : user-mode access to DCR */ static void gen_mfdcrux(DisasContext *ctx) { - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ @@ -5568,8 +5558,6 @@ static void gen_mfdcrux(DisasContext *ctx) /* mtdcrux (PPC 460) : user-mode access to DCR */ static void gen_mtdcrux(DisasContext *ctx) { - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ From 57a2988b6f750548052254c20796be6d87d2ab9f Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:36 +1000 Subject: [PATCH 32/64] ppc: Don't update NIP in facility unavailable interrupts This is no longer necessary as the helpers will properly retrieve the return address when needed. Also remove gen_update_current_nip() which didn't seem to make much sense to me. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/cpu.h | 1 - target-ppc/misc_helper.c | 9 +++++---- target-ppc/translate.c | 7 ------- target-ppc/translate_init.c | 2 -- 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index a872efb887..1e808c8884 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1202,7 +1202,6 @@ extern const struct VMStateDescription vmstate_ppc_cpu; PowerPCCPU *cpu_ppc_init(const char *cpu_model); void ppc_translate_init(void); const char *ppc_cpu_lookup_alias(const char *alias); -void gen_update_current_nip(void *opaque); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c index cb5ebf56cf..1e6e705a4e 100644 --- a/target-ppc/misc_helper.c +++ b/target-ppc/misc_helper.c @@ -39,7 +39,8 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn) #ifdef TARGET_PPC64 static void raise_fu_exception(CPUPPCState *env, uint32_t bit, - uint32_t sprn, uint32_t cause) + uint32_t sprn, uint32_t cause, + uintptr_t raddr) { qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit); @@ -47,7 +48,7 @@ static void raise_fu_exception(CPUPPCState *env, uint32_t bit, cause &= FSCR_IC_MASK; env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS; - helper_raise_exception_err(env, POWERPC_EXCP_FU, 0); + raise_exception_err_ra(env, POWERPC_EXCP_FU, 0, raddr); } #endif @@ -59,7 +60,7 @@ void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit, /* Facility is enabled, continue */ return; } - raise_fu_exception(env, bit, sprn, cause); + raise_fu_exception(env, bit, sprn, cause, GETPC()); #endif } @@ -71,7 +72,7 @@ void helper_msr_facility_check(CPUPPCState *env, uint32_t bit, /* Facility is enabled, continue */ return; } - raise_fu_exception(env, bit, sprn, cause); + raise_fu_exception(env, bit, sprn, cause, GETPC()); #endif } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 46b0e188c2..b62772b5eb 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -266,13 +266,6 @@ static inline void gen_update_nip(DisasContext *ctx, target_ulong nip) tcg_gen_movi_tl(cpu_nip, nip); } -void gen_update_current_nip(void *opaque) -{ - DisasContext *ctx = opaque; - - tcg_gen_movi_tl(cpu_nip, ctx->nip); -} - static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error) { TCGv_i32 t0, t1; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 293cc3d3d8..407ccb93a3 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7470,7 +7470,6 @@ static void gen_fscr_facility_check(DisasContext *ctx, int facility_sprn, TCGv_i32 t2 = tcg_const_i32(sprn); TCGv_i32 t3 = tcg_const_i32(cause); - gen_update_current_nip(ctx); gen_helper_fscr_facility_check(cpu_env, t1, t2, t3); tcg_temp_free_i32(t3); @@ -7485,7 +7484,6 @@ static void gen_msr_facility_check(DisasContext *ctx, int facility_sprn, TCGv_i32 t2 = tcg_const_i32(sprn); TCGv_i32 t3 = tcg_const_i32(cause); - gen_update_current_nip(ctx); gen_helper_msr_facility_check(cpu_env, t1, t2, t3); tcg_temp_free_i32(t3); From 8c8966e2188ade13c4ab9d3f8f4b12c99be0ade4 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:37 +1000 Subject: [PATCH 33/64] ppc: Don't update NIP BookE 2.06 tlbwe This is no longer necessary as the helpers will properly retrieve the return address when needed. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/mmu_helper.c | 12 ++++++------ target-ppc/translate.c | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 692398c3f0..696bb03ab5 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -2598,9 +2598,9 @@ void helper_booke206_tlbwe(CPUPPCState *env) tlb = booke206_cur_tlb(env); if (!tlb) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | - POWERPC_EXCP_INVAL_INVAL); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL, GETPC()); } /* check that we support the targeted size */ @@ -2608,9 +2608,9 @@ void helper_booke206_tlbwe(CPUPPCState *env) size_ps = booke206_tlbnps(env, tlbn); if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) && !(size_ps & (1 << size_tlb))) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | - POWERPC_EXCP_INVAL_INVAL); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL, GETPC()); } if (msr_gs) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index b62772b5eb..f75cdc6bb6 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -5849,7 +5849,6 @@ static void gen_tlbwe_booke206(DisasContext *ctx) GEN_PRIV; #else CHK_SV; - gen_update_nip(ctx, ctx->nip - 4); gen_helper_booke206_tlbwe(cpu_env); #endif /* defined(CONFIG_USER_ONLY) */ } From 72073dcce0ad1e84b866e45bc60ccf459aa9fcd4 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:38 +1000 Subject: [PATCH 34/64] ppc: Don't update NIP on conditional trap instructions This is no longer necessary as the helpers will properly retrieve the return address when needed. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/excp_helper.c | 6 ++++-- target-ppc/translate.c | 8 -------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index d31eece4dd..882d529dbe 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -1031,7 +1031,8 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { - raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_TRAP, GETPC()); } } @@ -1044,7 +1045,8 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { - raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_TRAP, GETPC()); } } #endif diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f75cdc6bb6..93cd98c6ad 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3580,8 +3580,6 @@ static void gen_sc(DisasContext *ctx) static void gen_tw(DisasContext *ctx) { TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode)); - /* Update the nip since this might generate a trap exception */ - gen_update_nip(ctx, ctx->nip - 4); gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); tcg_temp_free_i32(t0); @@ -3592,8 +3590,6 @@ static void gen_twi(DisasContext *ctx) { TCGv t0 = tcg_const_tl(SIMM(ctx->opcode)); TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode)); - /* Update the nip since this might generate a trap exception */ - gen_update_nip(ctx, ctx->nip - 4); gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free_i32(t1); @@ -3604,8 +3600,6 @@ static void gen_twi(DisasContext *ctx) static void gen_td(DisasContext *ctx) { TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode)); - /* Update the nip since this might generate a trap exception */ - gen_update_nip(ctx, ctx->nip - 4); gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); tcg_temp_free_i32(t0); @@ -3616,8 +3610,6 @@ static void gen_tdi(DisasContext *ctx) { TCGv t0 = tcg_const_tl(SIMM(ctx->opcode)); TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode)); - /* Update the nip since this might generate a trap exception */ - gen_update_nip(ctx, ctx->nip - 4); gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free_i32(t1); From 573708e3292a501e7f86ab13878a2799a1ec73ab Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:39 +1000 Subject: [PATCH 35/64] ppc: Don't update NIP if not taking alignment exceptions Move the NIP update to after the conditional branch so that we don't do it if we aren't going to take the alignment exception Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 93cd98c6ad..6320ae5aa1 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2414,12 +2414,11 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask) TCGLabel *l1 = gen_new_label(); TCGv t0 = tcg_temp_new(); TCGv_i32 t1, t2; - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); tcg_gen_andi_tl(t0, EA, mask); tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); t1 = tcg_const_i32(POWERPC_EXCP_ALIGN); t2 = tcg_const_i32(0); + gen_update_nip(ctx, ctx->nip - 4); gen_helper_raise_exception_err(cpu_env, t1, t2); tcg_temp_free_i32(t1); tcg_temp_free_i32(t2); From b00a3b3648c32cd1d2baaeef6d6a81e8d9341259 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:40 +1000 Subject: [PATCH 36/64] ppc: Don't update NIP in dcbz and lscbx Instead, pass GETPC() result to the corresponding helpers. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/mem_helper.c | 9 +++++---- target-ppc/translate.c | 4 ---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index e20a53eb50..92a594c894 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -141,13 +141,14 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb, } } -static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size) +static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size, + uintptr_t raddr) { int i; addr &= ~(dcache_line_size - 1); for (i = 0; i < dcache_line_size; i += 4) { - cpu_stl_data(env, addr + i, 0); + cpu_stl_data_ra(env, addr + i, 0, raddr); } if (env->reserve_addr == addr) { env->reserve_addr = (target_ulong)-1ULL; @@ -168,7 +169,7 @@ void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl) /* XXX add e500mc support */ - do_dcbz(env, addr, dcbz_size); + do_dcbz(env, addr, dcbz_size, GETPC()); } void helper_icbi(CPUPPCState *env, target_ulong addr) @@ -190,7 +191,7 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, d = 24; for (i = 0; i < xer_bc; i++) { - c = cpu_ldub_data(env, addr); + c = cpu_ldub_data_ra(env, addr, GETPC()); addr = addr_add(env, addr, 1); /* ra (if not 0) and rb are never modified */ if (likely(reg != rb && (ra == 0 || reg != ra))) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 6320ae5aa1..bebd1cc490 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4055,8 +4055,6 @@ static void gen_dcbz(DisasContext *ctx) int is_dcbzl = ctx->opcode & 0x00200000 ? 1 : 0; gen_set_access_type(ctx, ACCESS_CACHE); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); tcgv_addr = tcg_temp_new(); tcgv_is_dcbzl = tcg_const_i32(is_dcbzl); @@ -4584,8 +4582,6 @@ static void gen_lscbx(DisasContext *ctx) TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode)); gen_addr_reg_index(ctx, t0); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_helper_lscbx(t0, cpu_env, t0, t1, t2, t3); tcg_temp_free_i32(t1); tcg_temp_free_i32(t2); From 3433b732a4c9abb413eb39a6badb63e83ad2288c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:41 +1000 Subject: [PATCH 37/64] ppc: Make alignment exceptions suck less The current alignment exception generation tries to load the opcode to put in DSISR from a context where a cpu_ldl_code() is really not a good idea. It might fault and longjmp out and that's not something we want happening here. Instead, pass the releavant opcode bits via the error_code. There are a couple of cases of alignment interrupts that won't set anything, the ones coming from access to direct store segments, but that doesn't happen in practice, nobody used direct store segments and they are gone from newer chips. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/excp_helper.c | 9 +++++---- target-ppc/translate.c | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 882d529dbe..04ed4da1f4 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -260,11 +260,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } break; case POWERPC_EXCP_ALIGN: /* Alignment exception */ - /* XXX: this is false */ /* Get rS/rD and rA from faulting opcode */ - /* Broken for LE mode */ - env->spr[SPR_DSISR] |= (cpu_ldl_code(env, env->nip) - & 0x03FF0000) >> 16; + /* Note: the opcode fields will not be set properly for a direct + * store load/store, but nobody cares as nobody actually uses + * direct store segments. + */ + env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; break; case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index bebd1cc490..6bb0ba97ac 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2417,7 +2417,7 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask) tcg_gen_andi_tl(t0, EA, mask); tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); t1 = tcg_const_i32(POWERPC_EXCP_ALIGN); - t2 = tcg_const_i32(0); + t2 = tcg_const_i32(ctx->opcode & 0x03FF0000); gen_update_nip(ctx, ctx->nip - 4); gen_helper_raise_exception_err(cpu_env, t1, t2); tcg_temp_free_i32(t1); From 22b56ee5682e64509621f9d5d303a0414e289b11 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:42 +1000 Subject: [PATCH 38/64] ppc: Handle unconditional (always/never) traps at translation time We don't need to call a helper for trap always and trap never which are used by Linux under some circumstances. Signed-off-by: Benjamin Herrenschmidt -- v2. Don't generate the helper call when trapping always Signed-off-by: David Gibson --- target-ppc/translate.c | 49 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 6bb0ba97ac..7aa8d77972 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3575,10 +3575,30 @@ static void gen_sc(DisasContext *ctx) /*** Trap ***/ +/* Check for unconditional traps (always or never) */ +static bool check_unconditional_trap(DisasContext *ctx) +{ + /* Trap never */ + if (TO(ctx->opcode) == 0) { + return true; + } + /* Trap always */ + if (TO(ctx->opcode) == 31) { + gen_exception_err(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); + return true; + } + return false; +} + /* tw */ static void gen_tw(DisasContext *ctx) { - TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode)); + TCGv_i32 t0; + + if (check_unconditional_trap(ctx)) { + return; + } + t0 = tcg_const_i32(TO(ctx->opcode)); gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); tcg_temp_free_i32(t0); @@ -3587,8 +3607,14 @@ static void gen_tw(DisasContext *ctx) /* twi */ static void gen_twi(DisasContext *ctx) { - TCGv t0 = tcg_const_tl(SIMM(ctx->opcode)); - TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode)); + TCGv t0; + TCGv_i32 t1; + + if (check_unconditional_trap(ctx)) { + return; + } + t0 = tcg_const_tl(SIMM(ctx->opcode)); + t1 = tcg_const_i32(TO(ctx->opcode)); gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free_i32(t1); @@ -3598,7 +3624,12 @@ static void gen_twi(DisasContext *ctx) /* td */ static void gen_td(DisasContext *ctx) { - TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode)); + TCGv_i32 t0; + + if (check_unconditional_trap(ctx)) { + return; + } + t0 = tcg_const_i32(TO(ctx->opcode)); gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); tcg_temp_free_i32(t0); @@ -3607,8 +3638,14 @@ static void gen_td(DisasContext *ctx) /* tdi */ static void gen_tdi(DisasContext *ctx) { - TCGv t0 = tcg_const_tl(SIMM(ctx->opcode)); - TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode)); + TCGv t0; + TCGv_i32 t1; + + if (check_unconditional_trap(ctx)) { + return; + } + t0 = tcg_const_tl(SIMM(ctx->opcode)); + t1 = tcg_const_i32(TO(ctx->opcode)); gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free_i32(t1); From c9f82d013be0d8d9c5d9f51bb76e337a0a5a5cac Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:43 +1000 Subject: [PATCH 39/64] ppc: Speed up dcbz Use tlb_vaddr_to_host to do a fast path single translate for the whole cache line. Also make the reservation check match the entire range. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/mem_helper.c | 46 ++++++++++++++++++++++------------------- target-ppc/translate.c | 11 ++++------ 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index 92a594c894..6548715831 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -141,35 +141,39 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb, } } -static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size, - uintptr_t raddr) +void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode) { - int i; - - addr &= ~(dcache_line_size - 1); - for (i = 0; i < dcache_line_size; i += 4) { - cpu_stl_data_ra(env, addr + i, 0, raddr); - } - if (env->reserve_addr == addr) { - env->reserve_addr = (target_ulong)-1ULL; - } -} - -void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl) -{ - int dcbz_size = env->dcache_line_size; + target_ulong mask, dcbz_size = env->dcache_line_size; + uint32_t i; + void *haddr; #if defined(TARGET_PPC64) - if (!is_dcbzl && - (env->excp_model == POWERPC_EXCP_970) && - ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) { + /* Check for dcbz vs dcbzl on 970 */ + if (env->excp_model == POWERPC_EXCP_970 && + !(opcode & 0x00200000) && ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) { dcbz_size = 32; } #endif - /* XXX add e500mc support */ + /* Align address */ + mask = ~(dcbz_size - 1); + addr &= mask; - do_dcbz(env, addr, dcbz_size, GETPC()); + /* Check reservation */ + if ((env->reserve_addr & mask) == (addr & mask)) { + env->reserve_addr = (target_ulong)-1ULL; + } + + /* Try fast path translate */ + haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx); + if (haddr) { + memset(haddr, 0, dcbz_size); + } else { + /* Slow path */ + for (i = 0; i < dcbz_size; i += 8) { + cpu_stq_data_ra(env, addr + i, 0, GETPC()); + } + } } void helper_icbi(CPUPPCState *env, target_ulong addr) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 7aa8d77972..ac2c79bf28 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4088,18 +4088,15 @@ static void gen_dcbtls(DisasContext *ctx) static void gen_dcbz(DisasContext *ctx) { TCGv tcgv_addr; - TCGv_i32 tcgv_is_dcbzl; - int is_dcbzl = ctx->opcode & 0x00200000 ? 1 : 0; + TCGv_i32 tcgv_op; gen_set_access_type(ctx, ACCESS_CACHE); tcgv_addr = tcg_temp_new(); - tcgv_is_dcbzl = tcg_const_i32(is_dcbzl); - + tcgv_op = tcg_const_i32(ctx->opcode & 0x03FF000); gen_addr_reg_index(ctx, tcgv_addr); - gen_helper_dcbz(cpu_env, tcgv_addr, tcgv_is_dcbzl); - + gen_helper_dcbz(cpu_env, tcgv_addr, tcgv_op); tcg_temp_free(tcgv_addr); - tcg_temp_free_i32(tcgv_is_dcbzl); + tcg_temp_free_i32(tcgv_op); } /* dst / dstt */ From fbc3b39b3974bd6d3960376a1d4898adbbd47787 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:44 +1000 Subject: [PATCH 40/64] ppc: Fix CFAR updates We were one instruction off Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index ac2c79bf28..bc5b2ee97f 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3346,7 +3346,7 @@ static void gen_b(DisasContext *ctx) if (LK(ctx->opcode)) { gen_setlr(ctx, ctx->nip); } - gen_update_cfar(ctx, ctx->nip); + gen_update_cfar(ctx, ctx->nip - 4); gen_goto_tb(ctx, 0, target); } @@ -3411,7 +3411,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) } tcg_temp_free_i32(temp); } - gen_update_cfar(ctx, ctx->nip); + gen_update_cfar(ctx, ctx->nip - 4); if (type == BCOND_IM) { target_ulong li = (target_long)((int16_t)(BD(ctx->opcode))); if (likely(AA(ctx->opcode) == 0)) { @@ -3526,7 +3526,7 @@ static void gen_rfi(DisasContext *ctx) */ /* Restore CPU state */ CHK_SV; - gen_update_cfar(ctx, ctx->nip); + gen_update_cfar(ctx, ctx->nip - 4); gen_helper_rfi(cpu_env); gen_sync_exception(ctx); #endif @@ -3540,7 +3540,7 @@ static void gen_rfid(DisasContext *ctx) #else /* Restore CPU state */ CHK_SV; - gen_update_cfar(ctx, ctx->nip); + gen_update_cfar(ctx, ctx->nip - 4); gen_helper_rfid(cpu_env); gen_sync_exception(ctx); #endif From 5f2a6254522bd4cfb917822f678b117e6f005664 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:46 +1000 Subject: [PATCH 41/64] ppc: Don't set access_type on all load/stores on hash64 We don't use it so let's not generate the updates. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index bc5b2ee97f..59864356b1 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -195,6 +195,7 @@ struct DisasContext { /* Routine used to access memory */ bool pr, hv, dr, le_mode; bool lazy_tlb_flush; + bool need_access_type; int mem_idx; int access_type; /* Translation flags */ @@ -252,7 +253,7 @@ struct opc_handler_t { static inline void gen_set_access_type(DisasContext *ctx, int access_type) { - if (ctx->access_type != access_type) { + if (ctx->need_access_type && ctx->access_type != access_type) { tcg_gen_movi_i32(cpu_access_type, access_type); ctx->access_type = access_type; } @@ -6927,6 +6928,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.insns_flags = env->insns_flags; ctx.insns_flags2 = env->insns_flags2; ctx.access_type = -1; + ctx.need_access_type = !(env->mmu_model & POWERPC_MMU_64B); ctx.le_mode = !!(env->hflags & (1 << MSR_LE)); ctx.default_tcg_memop_mask = ctx.le_mode ? MO_LE : MO_BE; #if defined(TARGET_PPC64) From 65f2475f1f3b46086dfeef9ba882ea3d9d909d57 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:47 +1000 Subject: [PATCH 42/64] ppc: Use a helper to generate "LE unsupported" alignment interrupts Some operations aren't allowed in LE mode, use a helper rather than open coding the exception generation. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 59864356b1..1315656448 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2427,6 +2427,12 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask) tcg_temp_free(t0); } +static inline void gen_align_no_le(DisasContext *ctx) +{ + gen_exception_err(ctx, POWERPC_EXCP_ALIGN, + (ctx->opcode & 0x03FF0000) | POWERPC_EXCP_ALIGN_LE); +} + /*** Integer load ***/ static inline void gen_qemu_ld8u(DisasContext *ctx, TCGv arg1, TCGv arg2) { @@ -2647,10 +2653,9 @@ static void gen_lq(DisasContext *ctx) } if (!le_is_supported && ctx->le_mode) { - gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE); + gen_align_no_le(ctx); return; } - ra = rA(ctx->opcode); rd = rD(ctx->opcode); if (unlikely((rd & 1) || rd == ra)) { @@ -2781,7 +2786,7 @@ static void gen_std(DisasContext *ctx) } if (!le_is_supported && ctx->le_mode) { - gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE); + gen_align_no_le(ctx); return; } From 5817355ed0d989c72713d89c8d1e9133ec376485 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 27 Jul 2016 16:56:48 +1000 Subject: [PATCH 43/64] ppc: load/store multiple and string insns don't do LE Just generate an alignment interrupt Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1315656448..379d3d46c4 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2889,6 +2889,11 @@ static void gen_lmw(DisasContext *ctx) { TCGv t0; TCGv_i32 t1; + + if (ctx->le_mode) { + gen_align_no_le(ctx); + return; + } gen_set_access_type(ctx, ACCESS_INT); t0 = tcg_temp_new(); t1 = tcg_const_i32(rD(ctx->opcode)); @@ -2903,6 +2908,11 @@ static void gen_stmw(DisasContext *ctx) { TCGv t0; TCGv_i32 t1; + + if (ctx->le_mode) { + gen_align_no_le(ctx); + return; + } gen_set_access_type(ctx, ACCESS_INT); t0 = tcg_temp_new(); t1 = tcg_const_i32(rS(ctx->opcode)); @@ -2929,6 +2939,10 @@ static void gen_lswi(DisasContext *ctx) int ra = rA(ctx->opcode); int nr; + if (ctx->le_mode) { + gen_align_no_le(ctx); + return; + } if (nb == 0) nb = 32; nr = (nb + 3) / 4; @@ -2952,6 +2966,11 @@ static void gen_lswx(DisasContext *ctx) { TCGv t0; TCGv_i32 t1, t2, t3; + + if (ctx->le_mode) { + gen_align_no_le(ctx); + return; + } gen_set_access_type(ctx, ACCESS_INT); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); @@ -2971,6 +2990,11 @@ static void gen_stswi(DisasContext *ctx) TCGv t0; TCGv_i32 t1, t2; int nb = NB(ctx->opcode); + + if (ctx->le_mode) { + gen_align_no_le(ctx); + return; + } gen_set_access_type(ctx, ACCESS_INT); t0 = tcg_temp_new(); gen_addr_register(ctx, t0); @@ -2989,6 +3013,11 @@ static void gen_stswx(DisasContext *ctx) { TCGv t0; TCGv_i32 t1, t2; + + if (ctx->le_mode) { + gen_align_no_le(ctx); + return; + } gen_set_access_type(ctx, ACCESS_INT); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); From b07c32dc4bdda102803ed6699438fef059c8f408 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 28 Jul 2016 23:44:11 +0530 Subject: [PATCH 44/64] target-ppc: implement branch-less divw[o][.] While implementing modulo instructions figured out that the implementation uses many branches. Change the logic to achieve the branch-less code. Undefined value is set to dividend in case of invalid input. Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate.c | 48 ++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 379d3d46c4..f69836d153 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1097,41 +1097,39 @@ static void gen_addpcis(DisasContext *ctx) static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2, int sign, int compute_ov) { - TCGLabel *l1 = gen_new_label(); - TCGLabel *l2 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_local_new_i32(); - TCGv_i32 t1 = tcg_temp_local_new_i32(); + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(t0, arg1); tcg_gen_trunc_tl_i32(t1, arg2); - tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 0, l1); if (sign) { - TCGLabel *l3 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, t1, -1, l3); - tcg_gen_brcondi_i32(TCG_COND_EQ, t0, INT32_MIN, l1); - gen_set_label(l3); - tcg_gen_div_i32(t0, t0, t1); + tcg_gen_setcondi_i32(TCG_COND_EQ, t2, t0, INT_MIN); + tcg_gen_setcondi_i32(TCG_COND_EQ, t3, t1, -1); + tcg_gen_and_i32(t2, t2, t3); + tcg_gen_setcondi_i32(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_i32(t2, t2, t3); + tcg_gen_movi_i32(t3, 0); + tcg_gen_movcond_i32(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_div_i32(t3, t0, t1); + tcg_gen_extu_i32_tl(ret, t3); } else { - tcg_gen_divu_i32(t0, t0, t1); + tcg_gen_setcondi_i32(TCG_COND_EQ, t2, t1, 0); + tcg_gen_movi_i32(t3, 0); + tcg_gen_movcond_i32(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_divu_i32(t3, t0, t1); + tcg_gen_extu_i32_tl(ret, t3); } if (compute_ov) { - tcg_gen_movi_tl(cpu_ov, 0); + tcg_gen_extu_i32_tl(cpu_ov, t2); + tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov); } - tcg_gen_br(l2); - gen_set_label(l1); - if (sign) { - tcg_gen_sari_i32(t0, t0, 31); - } else { - tcg_gen_movi_i32(t0, 0); - } - if (compute_ov) { - tcg_gen_movi_tl(cpu_ov, 1); - tcg_gen_movi_tl(cpu_so, 1); - } - gen_set_label(l2); - tcg_gen_extu_i32_tl(ret, t0); tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, ret); } From 4110b586defd8499041275a9eca66264c344e823 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 28 Jul 2016 23:44:12 +0530 Subject: [PATCH 45/64] target-ppc: implement branch-less divd[o][.] Similar to divw, implement branch-less divd. Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate.c | 48 +++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f69836d153..5fe7a9dbce 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1170,37 +1170,41 @@ GEN_DIVE(divweo, divwe, 1); static inline void gen_op_arith_divd(DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2, int sign, int compute_ov) { - TCGLabel *l1 = gen_new_label(); - TCGLabel *l2 = gen_new_label(); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); - tcg_gen_brcondi_i64(TCG_COND_EQ, arg2, 0, l1); + tcg_gen_mov_i64(t0, arg1); + tcg_gen_mov_i64(t1, arg2); if (sign) { - TCGLabel *l3 = gen_new_label(); - tcg_gen_brcondi_i64(TCG_COND_NE, arg2, -1, l3); - tcg_gen_brcondi_i64(TCG_COND_EQ, arg1, INT64_MIN, l1); - gen_set_label(l3); - tcg_gen_div_i64(ret, arg1, arg2); + tcg_gen_setcondi_i64(TCG_COND_EQ, t2, t0, INT64_MIN); + tcg_gen_setcondi_i64(TCG_COND_EQ, t3, t1, -1); + tcg_gen_and_i64(t2, t2, t3); + tcg_gen_setcondi_i64(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_i64(t2, t2, t3); + tcg_gen_movi_i64(t3, 0); + tcg_gen_movcond_i64(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_div_i64(ret, t0, t1); } else { - tcg_gen_divu_i64(ret, arg1, arg2); + tcg_gen_setcondi_i64(TCG_COND_EQ, t2, t1, 0); + tcg_gen_movi_i64(t3, 0); + tcg_gen_movcond_i64(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_divu_i64(ret, t0, t1); } if (compute_ov) { - tcg_gen_movi_tl(cpu_ov, 0); + tcg_gen_mov_tl(cpu_ov, t2); + tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov); } - tcg_gen_br(l2); - gen_set_label(l1); - if (sign) { - tcg_gen_sari_i64(ret, arg1, 63); - } else { - tcg_gen_movi_i64(ret, 0); - } - if (compute_ov) { - tcg_gen_movi_tl(cpu_ov, 1); - tcg_gen_movi_tl(cpu_so, 1); - } - gen_set_label(l2); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); + if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, ret); } + #define GEN_INT_ARITH_DIVD(name, opc3, sign, compute_ov) \ static void glue(gen_, name)(DisasContext *ctx) \ { \ From 217f6b88058fa5509ff721741862e26db071929a Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Thu, 28 Jul 2016 23:44:13 +0530 Subject: [PATCH 46/64] target-ppc: add dtstsfi[q] instructions DFP Test Significance Immediate [Quad] Signed-off-by: Sandipan Das Signed-off-by: Nikunj A Dadhania Reviewed-by: David Gibson Signed-off-by: David Gibson --- target-ppc/dfp_helper.c | 35 +++++++++++++++++++++++++++++++++ target-ppc/helper.h | 2 ++ target-ppc/translate/dfp-impl.c | 20 +++++++++++++++++++ target-ppc/translate/dfp-ops.c | 14 +++++++++++++ 4 files changed, 71 insertions(+) diff --git a/target-ppc/dfp_helper.c b/target-ppc/dfp_helper.c index db0ede698b..9164fe701b 100644 --- a/target-ppc/dfp_helper.c +++ b/target-ppc/dfp_helper.c @@ -647,6 +647,41 @@ uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ DFP_HELPER_TSTSF(dtstsf, 64) DFP_HELPER_TSTSF(dtstsfq, 128) +#define DFP_HELPER_TSTSFI(op, size) \ +uint32_t helper_##op(CPUPPCState *env, uint32_t a, uint64_t *b) \ +{ \ + struct PPC_DFP dfp; \ + unsigned uim; \ + \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + \ + uim = a & 0x3F; \ + \ + if (unlikely(decNumberIsSpecial(&dfp.b))) { \ + dfp.crbf = 1; \ + } else if (uim == 0) { \ + dfp.crbf = 4; \ + } else if (unlikely(decNumberIsZero(&dfp.b))) { \ + /* Zero has no sig digits */ \ + dfp.crbf = 4; \ + } else { \ + unsigned nsd = dfp.b.digits; \ + if (uim < nsd) { \ + dfp.crbf = 8; \ + } else if (uim > nsd) { \ + dfp.crbf = 4; \ + } else { \ + dfp.crbf = 2; \ + } \ + } \ + \ + dfp_set_FPCC_from_CRBF(&dfp); \ + return dfp.crbf; \ +} + +DFP_HELPER_TSTSFI(dtstsfi, 64) +DFP_HELPER_TSTSFI(dtstsfiq, 128) + static void QUA_PPs(struct PPC_DFP *dfp) { dfp_set_FPRF_from_FRT(dfp); diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 9e4bb7b27d..68fd19ec8d 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -645,6 +645,8 @@ DEF_HELPER_3(dtstex, i32, env, fprp, fprp) DEF_HELPER_3(dtstexq, i32, env, fprp, fprp) DEF_HELPER_3(dtstsf, i32, env, fprp, fprp) DEF_HELPER_3(dtstsfq, i32, env, fprp, fprp) +DEF_HELPER_3(dtstsfi, i32, env, i32, fprp) +DEF_HELPER_3(dtstsfiq, i32, env, i32, fprp) DEF_HELPER_5(dquai, void, env, fprp, fprp, i32, i32) DEF_HELPER_5(dquaiq, void, env, fprp, fprp, i32, i32) DEF_HELPER_5(dqua, void, env, fprp, fprp, fprp, i32) diff --git a/target-ppc/translate/dfp-impl.c b/target-ppc/translate/dfp-impl.c index bf59951b1f..178d3044a7 100644 --- a/target-ppc/translate/dfp-impl.c +++ b/target-ppc/translate/dfp-impl.c @@ -45,6 +45,24 @@ static void gen_##name(DisasContext *ctx) \ tcg_temp_free_ptr(rb); \ } +#define GEN_DFP_BF_I_B(name) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i32 uim; \ + TCGv_ptr rb; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + uim = tcg_const_i32(UIMM5(ctx->opcode)); \ + rb = gen_fprp_ptr(rB(ctx->opcode)); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ + cpu_env, uim, rb); \ + tcg_temp_free_i32(uim); \ + tcg_temp_free_ptr(rb); \ +} + #define GEN_DFP_BF_A_DCM(name) \ static void gen_##name(DisasContext *ctx) \ { \ @@ -172,6 +190,8 @@ GEN_DFP_BF_A_B(dtstex) GEN_DFP_BF_A_B(dtstexq) GEN_DFP_BF_A_B(dtstsf) GEN_DFP_BF_A_B(dtstsfq) +GEN_DFP_BF_I_B(dtstsfi) +GEN_DFP_BF_I_B(dtstsfiq) GEN_DFP_T_B_U32_U32_Rc(dquai, SIMM5, RMC) GEN_DFP_T_B_U32_U32_Rc(dquaiq, SIMM5, RMC) GEN_DFP_T_A_B_I32_Rc(dqua, RMC) diff --git a/target-ppc/translate/dfp-ops.c b/target-ppc/translate/dfp-ops.c index 7f27d0f286..6ef38e5712 100644 --- a/target-ppc/translate/dfp-ops.c +++ b/target-ppc/translate/dfp-ops.c @@ -1,6 +1,9 @@ #define _GEN_DFP_LONG(name, op1, op2, mask) \ GEN_HANDLER_E(name, 0x3B, op1, op2, mask, PPC_NONE, PPC2_DFP) +#define _GEN_DFP_LONG_300(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3B, op1, op2, mask, PPC_NONE, PPC2_ISA300) + #define _GEN_DFP_LONGx2(name, op1, op2, mask) \ GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP) @@ -14,6 +17,9 @@ GEN_HANDLER_E(name, 0x3B, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP) #define _GEN_DFP_QUAD(name, op1, op2, mask) \ GEN_HANDLER_E(name, 0x3F, op1, op2, mask, PPC_NONE, PPC2_DFP) +#define _GEN_DFP_QUAD_300(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3F, op1, op2, mask, PPC_NONE, PPC2_ISA300) + #define _GEN_DFP_QUADx2(name, op1, op2, mask) \ GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP) @@ -48,12 +54,18 @@ _GEN_DFP_QUAD(name, op1, op2, 0x001F0800) #define GEN_DFP_BF_A_B(name, op1, op2) \ _GEN_DFP_LONG(name, op1, op2, 0x00000001) +#define GEN_DFP_BF_A_B_300(name, op1, op2) \ +_GEN_DFP_LONG_300(name, op1, op2, 0x00400001) + #define GEN_DFP_BF_Ap_Bp(name, op1, op2) \ _GEN_DFP_QUAD(name, op1, op2, 0x00610801) #define GEN_DFP_BF_A_Bp(name, op1, op2) \ _GEN_DFP_QUAD(name, op1, op2, 0x00600801) +#define GEN_DFP_BF_A_Bp_300(name, op1, op2) \ +_GEN_DFP_QUAD_300(name, op1, op2, 0x00400001) + #define GEN_DFP_BF_A_DCM(name, op1, op2) \ _GEN_DFP_LONGx2(name, op1, op2, 0x00600001) @@ -119,6 +131,8 @@ GEN_DFP_BF_A_B(dtstex, 0x02, 0x05), GEN_DFP_BF_Ap_Bp(dtstexq, 0x02, 0x05), GEN_DFP_BF_A_B(dtstsf, 0x02, 0x15), GEN_DFP_BF_A_Bp(dtstsfq, 0x02, 0x15), +GEN_DFP_BF_A_B_300(dtstsfi, 0x03, 0x15), +GEN_DFP_BF_A_Bp_300(dtstsfiq, 0x03, 0x15), GEN_DFP_TE_T_B_RMC_Rc(dquai, 0x03, 0x02), GEN_DFP_TE_Tp_Bp_RMC_Rc(dquaiq, 0x03, 0x02), GEN_DFP_T_A_B_RMC_Rc(dqua, 0x03, 0x00), From 377070595a5865a7db6fa671a1e84f149d80809a Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Thu, 28 Jul 2016 23:44:14 +0530 Subject: [PATCH 47/64] target-ppc: add vabsdu[b,h,w] instructions Adds following instructions: vabsdub: Vector Absolute Difference Unsigned Byte vabsduh: Vector Absolute Difference Unsigned Halfword vabsduw: Vector Absolute Difference Unsigned Word Signed-off-by: Sandipan Das [ use ISA300 define. Drop etype ] Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 3 +++ target-ppc/int_helper.c | 24 ++++++++++++++++++++++++ target-ppc/translate/vmx-impl.c | 9 +++++++++ target-ppc/translate/vmx-ops.c | 6 +++--- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 68fd19ec8d..ff6287e6b3 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -118,6 +118,9 @@ DEF_HELPER_3(vsubudm, void, avr, avr, avr) DEF_HELPER_3(vavgub, void, avr, avr, avr) DEF_HELPER_3(vavguh, void, avr, avr, avr) DEF_HELPER_3(vavguw, void, avr, avr, avr) +DEF_HELPER_3(vabsdub, void, avr, avr, avr) +DEF_HELPER_3(vabsduh, void, avr, avr, avr) +DEF_HELPER_3(vabsduw, void, avr, avr, avr) DEF_HELPER_3(vavgsb, void, avr, avr, avr) DEF_HELPER_3(vavgsh, void, avr, avr, avr) DEF_HELPER_3(vavgsw, void, avr, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 15947ad925..ef487d0b9c 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -629,6 +629,30 @@ VAVG(w, s32, int64_t, u32, uint64_t) #undef VAVG_DO #undef VAVG +#define VABSDU_DO(name, element) \ +void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ +{ \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + r->element[i] = (a->element[i] > b->element[i]) ? \ + (a->element[i] - b->element[i]) : \ + (b->element[i] - a->element[i]); \ + } \ +} + +/* VABSDU - Vector absolute difference unsigned + * name - instruction mnemonic suffix (b: byte, h: halfword, w: word) + * element - element type to access from vector + */ +#define VABSDU(type, element) \ + VABSDU_DO(absdu##type, element) +VABSDU(b, u8) +VABSDU(h, u16) +VABSDU(w, u32) +#undef VABSDU_DO +#undef VABSDU + #define VCF(suffix, cvt, element) \ void helper_vcf##suffix(CPUPPCState *env, ppc_avr_t *r, \ ppc_avr_t *b, uint32_t uim) \ diff --git a/target-ppc/translate/vmx-impl.c b/target-ppc/translate/vmx-impl.c index 110e19c88b..ad0345f1ac 100644 --- a/target-ppc/translate/vmx-impl.c +++ b/target-ppc/translate/vmx-impl.c @@ -301,8 +301,17 @@ GEN_VXFORM(vminsh, 1, 13); GEN_VXFORM(vminsw, 1, 14); GEN_VXFORM(vminsd, 1, 15); GEN_VXFORM(vavgub, 1, 16); +GEN_VXFORM(vabsdub, 1, 16); +GEN_VXFORM_DUAL(vavgub, PPC_ALTIVEC, PPC_NONE, \ + vabsdub, PPC_NONE, PPC2_ISA300) GEN_VXFORM(vavguh, 1, 17); +GEN_VXFORM(vabsduh, 1, 17); +GEN_VXFORM_DUAL(vavguh, PPC_ALTIVEC, PPC_NONE, \ + vabsduh, PPC_NONE, PPC2_ISA300) GEN_VXFORM(vavguw, 1, 18); +GEN_VXFORM(vabsduw, 1, 18); +GEN_VXFORM_DUAL(vavguw, PPC_ALTIVEC, PPC_NONE, \ + vabsduw, PPC_NONE, PPC2_ISA300) GEN_VXFORM(vavgsb, 1, 20); GEN_VXFORM(vavgsh, 1, 21); GEN_VXFORM(vavgsw, 1, 22); diff --git a/target-ppc/translate/vmx-ops.c b/target-ppc/translate/vmx-ops.c index 185dc71fb9..59016af35b 100644 --- a/target-ppc/translate/vmx-ops.c +++ b/target-ppc/translate/vmx-ops.c @@ -69,9 +69,9 @@ GEN_VXFORM(vminsb, 1, 12), GEN_VXFORM(vminsh, 1, 13), GEN_VXFORM(vminsw, 1, 14), GEN_VXFORM_207(vminsd, 1, 15), -GEN_VXFORM(vavgub, 1, 16), -GEN_VXFORM(vavguh, 1, 17), -GEN_VXFORM(vavguw, 1, 18), +GEN_VXFORM_DUAL(vavgub, vabsdub, 1, 16, PPC_ALTIVEC, PPC_NONE), +GEN_VXFORM_DUAL(vavguh, vabsduh, 1, 17, PPC_ALTIVEC, PPC_NONE), +GEN_VXFORM_DUAL(vavguw, vabsduw, 1, 18, PPC_ALTIVEC, PPC_NONE), GEN_VXFORM(vavgsb, 1, 20), GEN_VXFORM(vavgsh, 1, 21), GEN_VXFORM(vavgsw, 1, 22), From f7cc8466f1c29550b5ace0750813bc6c9190f604 Mon Sep 17 00:00:00 2001 From: Swapnil Bokade Date: Thu, 28 Jul 2016 23:44:15 +0530 Subject: [PATCH 48/64] target-ppc: add vcmpnez[b,h,w][.] instructions Adds following instructions: vcmpnezb[.]: Vector Compare Not Equal or Zero Byte vcmpnezh[.]: Vector Compare Not Equal or Zero Halfword vcmpnezw[.]: Vector Compare Not Equal or Zero Word Signed-off-by: Swapnil Bokade [ collapse switch case ] Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 6 ++++++ target-ppc/int_helper.c | 36 +++++++++++++++++++++++++++++++++ target-ppc/translate/vmx-impl.c | 3 +++ target-ppc/translate/vmx-ops.c | 9 +++++++++ 4 files changed, 54 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index ff6287e6b3..e93b84b9f0 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -144,6 +144,9 @@ DEF_HELPER_4(vcmpequb, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequh, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequw, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequd, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnezb, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnezh, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnezw, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgtub, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgtuh, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgtuw, void, env, avr, avr, avr) @@ -160,6 +163,9 @@ DEF_HELPER_4(vcmpequb_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequh_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequw_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequd_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnezb_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnezh_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnezw_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgtub_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgtuh_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgtuw_dot, void, env, avr, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index ef487d0b9c..9b4de6926b 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -719,6 +719,42 @@ VCMP(gtsd, >, s64) #undef VCMP_DO #undef VCMP +#define VCMPNEZ_DO(suffix, element, etype, record) \ +void helper_vcmpnez##suffix(CPUPPCState *env, ppc_avr_t *r, \ + ppc_avr_t *a, ppc_avr_t *b) \ +{ \ + etype ones = (etype)-1; \ + etype all = ones; \ + etype none = 0; \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + etype result = ((a->element[i] == 0) \ + || (b->element[i] == 0) \ + || (a->element[i] != b->element[i]) ? \ + ones : 0x0); \ + r->element[i] = result; \ + all &= result; \ + none |= result; \ + } \ + if (record) { \ + env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \ + } \ +} + +/* VCMPNEZ - Vector compare not equal to zero + * suffix - instruction mnemonic suffix (b: byte, h: halfword, w: word) + * element - element type to access from vector + */ +#define VCMPNEZ(suffix, element, etype) \ + VCMPNEZ_DO(suffix, element, etype, 0) \ + VCMPNEZ_DO(suffix##_dot, element, etype, 1) +VCMPNEZ(b, u8, uint8_t) +VCMPNEZ(h, u16, uint16_t) +VCMPNEZ(w, u32, uint32_t) +#undef VCMPNEZ_DO +#undef VCMPNEZ + #define VCMPFP_DO(suffix, compare, order, record) \ void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \ ppc_avr_t *a, ppc_avr_t *b) \ diff --git a/target-ppc/translate/vmx-impl.c b/target-ppc/translate/vmx-impl.c index ad0345f1ac..5cd007e7de 100644 --- a/target-ppc/translate/vmx-impl.c +++ b/target-ppc/translate/vmx-impl.c @@ -493,6 +493,9 @@ GEN_VXRFORM(vcmpequb, 3, 0) GEN_VXRFORM(vcmpequh, 3, 1) GEN_VXRFORM(vcmpequw, 3, 2) GEN_VXRFORM(vcmpequd, 3, 3) +GEN_VXRFORM(vcmpnezb, 3, 4) +GEN_VXRFORM(vcmpnezh, 3, 5) +GEN_VXRFORM(vcmpnezw, 3, 6) GEN_VXRFORM(vcmpgtsb, 3, 12) GEN_VXRFORM(vcmpgtsh, 3, 13) GEN_VXRFORM(vcmpgtsw, 3, 14) diff --git a/target-ppc/translate/vmx-ops.c b/target-ppc/translate/vmx-ops.c index 59016af35b..0be69890d1 100644 --- a/target-ppc/translate/vmx-ops.c +++ b/target-ppc/translate/vmx-ops.c @@ -160,12 +160,21 @@ GEN_VXFORM(vminfp, 5, 17), #define GEN_VXRFORM1(opname, name, str, opc2, opc3) \ GEN_HANDLER2(name, str, 0x4, opc2, opc3, 0x00000000, PPC_ALTIVEC), +#define GEN_VXRFORM1_300(opname, name, str, opc2, opc3) \ +GEN_HANDLER2_E(name, str, 0x4, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ISA300), #define GEN_VXRFORM(name, opc2, opc3) \ GEN_VXRFORM1(name, name, #name, opc2, opc3) \ GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4))) +#define GEN_VXRFORM_300(name, opc2, opc3) \ + GEN_VXRFORM1_300(name, name, #name, opc2, opc3) \ + GEN_VXRFORM1_300(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4))) + GEN_VXRFORM(vcmpequb, 3, 0) GEN_VXRFORM(vcmpequh, 3, 1) GEN_VXRFORM(vcmpequw, 3, 2) +GEN_VXRFORM_300(vcmpnezb, 3, 4) +GEN_VXRFORM_300(vcmpnezh, 3, 5) +GEN_VXRFORM_300(vcmpnezw, 3, 6) GEN_VXRFORM(vcmpgtsb, 3, 12) GEN_VXRFORM(vcmpgtsh, 3, 13) GEN_VXRFORM(vcmpgtsw, 3, 14) From 5644a17567596eea8c4e16a8087dab9cc0292c6f Mon Sep 17 00:00:00 2001 From: Vivek Andrew Sha Date: Thu, 28 Jul 2016 23:44:16 +0530 Subject: [PATCH 49/64] target-ppc: add vslv instruction vslv: Vector Shift Left Variable Signed-off-by: Vivek Andrew Sha Signed-off-by: Nikunj A Dadhania Reviewed-by: David Gibson Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 1 + target-ppc/int_helper.c | 14 ++++++++++++++ target-ppc/translate/vmx-impl.c | 1 + target-ppc/translate/vmx-ops.c | 4 ++++ 4 files changed, 20 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index e93b84b9f0..9703f8502c 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -211,6 +211,7 @@ DEF_HELPER_3(vslw, void, avr, avr, avr) DEF_HELPER_3(vsld, void, avr, avr, avr) DEF_HELPER_3(vslo, void, avr, avr, avr) DEF_HELPER_3(vsro, void, avr, avr, avr) +DEF_HELPER_3(vslv, void, avr, avr, avr) DEF_HELPER_3(vaddcuw, void, avr, avr, avr) DEF_HELPER_3(vsubcuw, void, avr, avr, avr) DEF_HELPER_2(lvsl, void, avr, tl) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 9b4de6926b..12fe1448fa 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -1696,6 +1696,20 @@ VSL(w, u32, 0x1F) VSL(d, u64, 0x3F) #undef VSL +void helper_vslv(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int i; + unsigned int shift, bytes, size; + + size = ARRAY_SIZE(r->u8); + for (i = 0; i < size; i++) { + shift = b->u8[i] & 0x7; /* extract shift value */ + bytes = (a->u8[i] << 8) + /* extract adjacent bytes */ + (((i + 1) < size) ? a->u8[i + 1] : 0); + r->u8[i] = (bytes << shift) >> 8; /* shift and store result */ + } +} + void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift) { int sh = shift & 0xf; diff --git a/target-ppc/translate/vmx-impl.c b/target-ppc/translate/vmx-impl.c index 5cd007e7de..e979668750 100644 --- a/target-ppc/translate/vmx-impl.c +++ b/target-ppc/translate/vmx-impl.c @@ -383,6 +383,7 @@ GEN_VXFORM(vsrab, 2, 12); GEN_VXFORM(vsrah, 2, 13); GEN_VXFORM(vsraw, 2, 14); GEN_VXFORM(vsrad, 2, 15); +GEN_VXFORM(vslv, 2, 29); GEN_VXFORM(vslo, 6, 16); GEN_VXFORM(vsro, 6, 17); GEN_VXFORM(vaddcuw, 0, 6); diff --git a/target-ppc/translate/vmx-ops.c b/target-ppc/translate/vmx-ops.c index 0be69890d1..61e08b2f2d 100644 --- a/target-ppc/translate/vmx-ops.c +++ b/target-ppc/translate/vmx-ops.c @@ -38,6 +38,9 @@ GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) #define GEN_VXFORM_207(name, opc2, opc3) \ GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207) +#define GEN_VXFORM_300(name, opc2, opc3) \ +GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ISA300) + #define GEN_VXFORM_DUAL(name0, name1, opc2, opc3, type0, type1) \ GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, type0, type1) @@ -107,6 +110,7 @@ GEN_VXFORM(vsrab, 2, 12), GEN_VXFORM(vsrah, 2, 13), GEN_VXFORM(vsraw, 2, 14), GEN_VXFORM_207(vsrad, 2, 15), +GEN_VXFORM_300(vslv, 2, 29), GEN_VXFORM(vslo, 6, 16), GEN_VXFORM(vsro, 6, 17), GEN_VXFORM(vaddcuw, 0, 6), From 4004c1dbca3ac2399d51ba636b4de032448adc9f Mon Sep 17 00:00:00 2001 From: Vivek Andrew Sha Date: Thu, 28 Jul 2016 23:44:17 +0530 Subject: [PATCH 50/64] target-ppc: add vsrv instruction Adds Vector Shift Right Variable instruction. Signed-off-by: Vivek Andrew Sha [ reverse the order of computation to avoid temporary array ] Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 1 + target-ppc/int_helper.c | 17 +++++++++++++++++ target-ppc/translate/vmx-impl.c | 1 + target-ppc/translate/vmx-ops.c | 1 + 4 files changed, 20 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 9703f8502c..8eada2f889 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -211,6 +211,7 @@ DEF_HELPER_3(vslw, void, avr, avr, avr) DEF_HELPER_3(vsld, void, avr, avr, avr) DEF_HELPER_3(vslo, void, avr, avr, avr) DEF_HELPER_3(vsro, void, avr, avr, avr) +DEF_HELPER_3(vsrv, void, avr, avr, avr) DEF_HELPER_3(vslv, void, avr, avr, avr) DEF_HELPER_3(vaddcuw, void, avr, avr, avr) DEF_HELPER_3(vsubcuw, void, avr, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 12fe1448fa..552b2e041b 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -1710,6 +1710,23 @@ void helper_vslv(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } } +void helper_vsrv(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int i; + unsigned int shift, bytes; + + /* Use reverse order, as destination and source register can be same. Its + * being modified in place saving temporary, reverse order will guarantee + * that computed result is not fed back. + */ + for (i = ARRAY_SIZE(r->u8) - 1; i >= 0; i--) { + shift = b->u8[i] & 0x7; /* extract shift value */ + bytes = ((i ? a->u8[i - 1] : 0) << 8) + a->u8[i]; + /* extract adjacent bytes */ + r->u8[i] = (bytes >> shift) & 0xFF; /* shift and store result */ + } +} + void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift) { int sh = shift & 0xf; diff --git a/target-ppc/translate/vmx-impl.c b/target-ppc/translate/vmx-impl.c index e979668750..b9841222ea 100644 --- a/target-ppc/translate/vmx-impl.c +++ b/target-ppc/translate/vmx-impl.c @@ -383,6 +383,7 @@ GEN_VXFORM(vsrab, 2, 12); GEN_VXFORM(vsrah, 2, 13); GEN_VXFORM(vsraw, 2, 14); GEN_VXFORM(vsrad, 2, 15); +GEN_VXFORM(vsrv, 2, 28); GEN_VXFORM(vslv, 2, 29); GEN_VXFORM(vslo, 6, 16); GEN_VXFORM(vsro, 6, 17); diff --git a/target-ppc/translate/vmx-ops.c b/target-ppc/translate/vmx-ops.c index 61e08b2f2d..2a9f225e6a 100644 --- a/target-ppc/translate/vmx-ops.c +++ b/target-ppc/translate/vmx-ops.c @@ -110,6 +110,7 @@ GEN_VXFORM(vsrab, 2, 12), GEN_VXFORM(vsrah, 2, 13), GEN_VXFORM(vsraw, 2, 14), GEN_VXFORM_207(vsrad, 2, 15), +GEN_VXFORM_300(vsrv, 2, 28), GEN_VXFORM_300(vslv, 2, 29), GEN_VXFORM(vslo, 6, 16), GEN_VXFORM(vsro, 6, 17), From 787bbe3711725c66c2c24b0afad487beb76fe9e7 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 28 Jul 2016 23:44:18 +0530 Subject: [PATCH 51/64] target-ppc: add extswsli[.] instruction extswsli : Extend Sign Word & Shift Left Immediate Signed-off-by: Nikunj A Dadhania Reviewed-by: David Gibson Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 5fe7a9dbce..14f4b682f4 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2329,6 +2329,30 @@ static void gen_sradi1(DisasContext *ctx) gen_sradi(ctx, 1); } +/* extswsli & extswsli. */ +static inline void gen_extswsli(DisasContext *ctx, int n) +{ + int sh = SH(ctx->opcode) + (n << 5); + TCGv dst = cpu_gpr[rA(ctx->opcode)]; + TCGv src = cpu_gpr[rS(ctx->opcode)]; + + tcg_gen_ext32s_tl(dst, src); + tcg_gen_shli_tl(dst, dst, sh); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_Rc0(ctx, dst); + } +} + +static void gen_extswsli0(DisasContext *ctx) +{ + gen_extswsli(ctx, 0); +} + +static void gen_extswsli1(DisasContext *ctx) +{ + gen_extswsli(ctx, 1); +} + /* srd & srd. */ static void gen_srd(DisasContext *ctx) { @@ -6228,6 +6252,10 @@ GEN_HANDLER(srad, 0x1F, 0x1A, 0x18, 0x00000000, PPC_64B), GEN_HANDLER2(sradi0, "sradi", 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B), GEN_HANDLER2(sradi1, "sradi", 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B), GEN_HANDLER(srd, 0x1F, 0x1B, 0x10, 0x00000000, PPC_64B), +GEN_HANDLER2_E(extswsli0, "extswsli", 0x1F, 0x1A, 0x1B, 0x00000000, + PPC_NONE, PPC2_ISA300), +GEN_HANDLER2_E(extswsli1, "extswsli", 0x1F, 0x1B, 0x1B, 0x00000000, + PPC_NONE, PPC2_ISA300), #endif #if defined(TARGET_PPC64) GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B), From 15848410af5caccb7ca419654e46b0ce42d6bf4b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 1 Aug 2016 20:17:42 +1000 Subject: [PATCH 52/64] ppc: Rename #include'd .c files to .inc.c Also while at it, group the #include statements in translate.c Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- target-ppc/translate.c | 40 +++++++++---------- .../translate/{dfp-impl.c => dfp-impl.inc.c} | 0 .../translate/{dfp-ops.c => dfp-ops.inc.c} | 0 .../translate/{fp-impl.c => fp-impl.inc.c} | 0 .../translate/{fp-ops.c => fp-ops.inc.c} | 0 .../translate/{spe-impl.c => spe-impl.inc.c} | 0 .../translate/{spe-ops.c => spe-ops.inc.c} | 0 .../translate/{vmx-impl.c => vmx-impl.inc.c} | 0 .../translate/{vmx-ops.c => vmx-ops.inc.c} | 0 .../translate/{vsx-impl.c => vsx-impl.inc.c} | 0 .../translate/{vsx-ops.c => vsx-ops.inc.c} | 0 11 files changed, 20 insertions(+), 20 deletions(-) rename target-ppc/translate/{dfp-impl.c => dfp-impl.inc.c} (100%) rename target-ppc/translate/{dfp-ops.c => dfp-ops.inc.c} (100%) rename target-ppc/translate/{fp-impl.c => fp-impl.inc.c} (100%) rename target-ppc/translate/{fp-ops.c => fp-ops.inc.c} (100%) rename target-ppc/translate/{spe-impl.c => spe-impl.inc.c} (100%) rename target-ppc/translate/{spe-ops.c => spe-ops.inc.c} (100%) rename target-ppc/translate/{vmx-impl.c => vmx-impl.inc.c} (100%) rename target-ppc/translate/{vmx-ops.c => vmx-ops.inc.c} (100%) rename target-ppc/translate/{vsx-impl.c => vsx-impl.inc.c} (100%) rename target-ppc/translate/{vsx-ops.c => vsx-ops.inc.c} (100%) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 14f4b682f4..0a5a3e21f0 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -5316,12 +5316,6 @@ static void gen_rfsvc(DisasContext *ctx) #endif /* defined(CONFIG_USER_ONLY) */ } -#include "translate/fp-impl.c" - -#include "translate/vmx-impl.c" - -#include "translate/vsx-impl.c" - /* svc is not implemented for now */ /* BookE specific instructions */ @@ -6108,10 +6102,6 @@ static void gen_maddhd_maddhdu(DisasContext *ctx) } #endif /* defined(TARGET_PPC64) */ -#include "translate/dfp-impl.c" - -#include "translate/spe-impl.c" - static void gen_tbegin(DisasContext *ctx) { if (unlikely(!ctx->tm_enabled)) { @@ -6191,6 +6181,16 @@ static inline void gen_##name(DisasContext *ctx) \ GEN_TM_PRIV_NOOP(treclaim); GEN_TM_PRIV_NOOP(trechkpt); +#include "translate/fp-impl.inc.c" + +#include "translate/vmx-impl.inc.c" + +#include "translate/vsx-impl.inc.c" + +#include "translate/dfp-impl.inc.c" + +#include "translate/spe-impl.inc.c" + static opcode_t opcodes[] = { GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE), GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER), @@ -6715,16 +6715,6 @@ GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00), GEN_MAC_HANDLER(mullhw, 0x08, 0x0D), GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C), -#include "translate/fp-ops.c" - -#include "translate/vmx-ops.c" - -#include "translate/vsx-ops.c" - -#include "translate/dfp-ops.c" - -#include "translate/spe-ops.c" - GEN_HANDLER2_E(tbegin, "tbegin", 0x1F, 0x0E, 0x14, 0x01DFF800, \ PPC_NONE, PPC2_TM), GEN_HANDLER2_E(tend, "tend", 0x1F, 0x0E, 0x15, 0x01FFF800, \ @@ -6747,6 +6737,16 @@ GEN_HANDLER2_E(treclaim, "treclaim", 0x1F, 0x0E, 0x1D, 0x03E0F800, \ PPC_NONE, PPC2_TM), GEN_HANDLER2_E(trechkpt, "trechkpt", 0x1F, 0x0E, 0x1F, 0x03FFF800, \ PPC_NONE, PPC2_TM), + +#include "translate/fp-ops.inc.c" + +#include "translate/vmx-ops.inc.c" + +#include "translate/vsx-ops.inc.c" + +#include "translate/dfp-ops.inc.c" + +#include "translate/spe-ops.inc.c" }; #include "helper_regs.h" diff --git a/target-ppc/translate/dfp-impl.c b/target-ppc/translate/dfp-impl.inc.c similarity index 100% rename from target-ppc/translate/dfp-impl.c rename to target-ppc/translate/dfp-impl.inc.c diff --git a/target-ppc/translate/dfp-ops.c b/target-ppc/translate/dfp-ops.inc.c similarity index 100% rename from target-ppc/translate/dfp-ops.c rename to target-ppc/translate/dfp-ops.inc.c diff --git a/target-ppc/translate/fp-impl.c b/target-ppc/translate/fp-impl.inc.c similarity index 100% rename from target-ppc/translate/fp-impl.c rename to target-ppc/translate/fp-impl.inc.c diff --git a/target-ppc/translate/fp-ops.c b/target-ppc/translate/fp-ops.inc.c similarity index 100% rename from target-ppc/translate/fp-ops.c rename to target-ppc/translate/fp-ops.inc.c diff --git a/target-ppc/translate/spe-impl.c b/target-ppc/translate/spe-impl.inc.c similarity index 100% rename from target-ppc/translate/spe-impl.c rename to target-ppc/translate/spe-impl.inc.c diff --git a/target-ppc/translate/spe-ops.c b/target-ppc/translate/spe-ops.inc.c similarity index 100% rename from target-ppc/translate/spe-ops.c rename to target-ppc/translate/spe-ops.inc.c diff --git a/target-ppc/translate/vmx-impl.c b/target-ppc/translate/vmx-impl.inc.c similarity index 100% rename from target-ppc/translate/vmx-impl.c rename to target-ppc/translate/vmx-impl.inc.c diff --git a/target-ppc/translate/vmx-ops.c b/target-ppc/translate/vmx-ops.inc.c similarity index 100% rename from target-ppc/translate/vmx-ops.c rename to target-ppc/translate/vmx-ops.inc.c diff --git a/target-ppc/translate/vsx-impl.c b/target-ppc/translate/vsx-impl.inc.c similarity index 100% rename from target-ppc/translate/vsx-impl.c rename to target-ppc/translate/vsx-impl.inc.c diff --git a/target-ppc/translate/vsx-ops.c b/target-ppc/translate/vsx-ops.inc.c similarity index 100% rename from target-ppc/translate/vsx-ops.c rename to target-ppc/translate/vsx-ops.inc.c From ce9863b7978976492efc2b57589516f3fcae79cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 2 Aug 2016 19:38:00 +0200 Subject: [PATCH 53/64] hw/ppc: use error_report instead of fprintf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr.c | 12 ++++++------ hw/ppc/spapr_drc.c | 8 ++++---- hw/ppc/spapr_iommu.c | 4 ++-- hw/ppc/spapr_rtas.c | 13 +++++++------ hw/ppc/spapr_vio.c | 3 ++- include/hw/ppc/fdt.h | 8 +++++--- 6 files changed, 26 insertions(+), 22 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 79d136d194..7ec27511f5 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -647,13 +647,13 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size", pcc->l1_dcache_size))); } else { - fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n"); + error_report("Warning: Unknown L1 dcache size for cpu"); } if (pcc->l1_icache_size) { _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size", pcc->l1_icache_size))); } else { - fprintf(stderr, "Warning: Unknown L1 icache size for cpu\n"); + error_report("Warning: Unknown L1 icache size for cpu"); } _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); @@ -945,20 +945,20 @@ static void spapr_finalize_fdt(sPAPRMachineState *spapr, ret = spapr_populate_memory(spapr, fdt); if (ret < 0) { - fprintf(stderr, "couldn't setup memory nodes in fdt\n"); + error_report("couldn't setup memory nodes in fdt"); exit(1); } ret = spapr_populate_vdevice(spapr->vio_bus, fdt); if (ret < 0) { - fprintf(stderr, "couldn't setup vio devices in fdt\n"); + error_report("couldn't setup vio devices in fdt"); exit(1); } if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) { ret = spapr_rng_populate_dt(fdt); if (ret < 0) { - fprintf(stderr, "could not set up rng device in the fdt\n"); + error_report("could not set up rng device in the fdt"); exit(1); } } @@ -974,7 +974,7 @@ static void spapr_finalize_fdt(sPAPRMachineState *spapr, /* RTAS */ ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size); if (ret < 0) { - fprintf(stderr, "Couldn't set up RTAS device tree properties\n"); + error_report("Couldn't set up RTAS device tree properties"); } /* cpus */ diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 26a067951c..4b1a943b8e 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -816,7 +816,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, drc_indexes->data, drc_indexes->len * sizeof(uint32_t)); if (ret) { - fprintf(stderr, "Couldn't create ibm,drc-indexes property\n"); + error_report("Couldn't create ibm,drc-indexes property"); goto out; } @@ -824,21 +824,21 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, drc_power_domains->data, drc_power_domains->len * sizeof(uint32_t)); if (ret) { - fprintf(stderr, "Couldn't finalize ibm,drc-power-domains property\n"); + error_report("Couldn't finalize ibm,drc-power-domains property"); goto out; } ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-names", drc_names->str, drc_names->len); if (ret) { - fprintf(stderr, "Couldn't finalize ibm,drc-names property\n"); + error_report("Couldn't finalize ibm,drc-names property"); goto out; } ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-types", drc_types->str, drc_types->len); if (ret) { - fprintf(stderr, "Couldn't finalize ibm,drc-types property\n"); + error_report("Couldn't finalize ibm,drc-types property"); goto out; } diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 6bc4d4db33..f20b0b884f 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -310,8 +310,8 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn) char tmp[32]; if (spapr_tce_find_by_liobn(liobn)) { - fprintf(stderr, "Attempted to create TCE table with duplicate" - " LIOBN 0x%x\n", liobn); + error_report("Attempted to create TCE table with duplicate" + " LIOBN 0x%x", liobn); return NULL; } diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index dc058e512b..27b5ad4bc4 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -27,6 +27,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "qemu/log.h" +#include "qemu/error-report.h" #include "sysemu/sysemu.h" #include "sysemu/char.h" #include "hw/qdev.h" @@ -716,7 +717,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size); if (ret < 0) { - fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n", + error_report("Couldn't add RTAS reserve entry: %s", fdt_strerror(ret)); return ret; } @@ -724,7 +725,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-base", rtas_addr); if (ret < 0) { - fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n", + error_report("Couldn't add linux,rtas-base property: %s", fdt_strerror(ret)); return ret; } @@ -732,7 +733,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-entry", rtas_addr); if (ret < 0) { - fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n", + error_report("Couldn't add linux,rtas-entry property: %s", fdt_strerror(ret)); return ret; } @@ -740,7 +741,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, ret = qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size", rtas_size); if (ret < 0) { - fprintf(stderr, "Couldn't add rtas-size property: %s\n", + error_report("Couldn't add rtas-size property: %s", fdt_strerror(ret)); return ret; } @@ -755,7 +756,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name, i + RTAS_TOKEN_BASE); if (ret < 0) { - fprintf(stderr, "Couldn't add rtas token for %s: %s\n", + error_report("Couldn't add rtas token for %s: %s", call->name, fdt_strerror(ret)); return ret; } @@ -770,7 +771,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, ret = qemu_fdt_setprop(fdt, "/rtas", "ibm,lrdr-capacity", lrdr_capacity, sizeof(lrdr_capacity)); if (ret < 0) { - fprintf(stderr, "Couldn't add ibm,lrdr-capacity rtas property\n"); + error_report("Couldn't add ibm,lrdr-capacity rtas property"); return ret; } diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index f93244d7c1..497028f075 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -20,6 +20,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "hw/hw.h" #include "qemu/log.h" @@ -276,7 +277,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) uint8_t byte; if (!dev->crq.qsize) { - fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n"); + error_report("spapr_vio_send_creq on uninitialized queue"); return -1; } diff --git a/include/hw/ppc/fdt.h b/include/hw/ppc/fdt.h index fff3e1b577..2e5c61af14 100644 --- a/include/hw/ppc/fdt.h +++ b/include/hw/ppc/fdt.h @@ -10,11 +10,13 @@ #ifndef PPC_FDT_H #define PPC_FDT_H -#define _FDT(exp) \ - do { \ +#include "qemu/error-report.h" + +#define _FDT(exp) \ + do { \ int ret = (exp); \ if (ret < 0) { \ - fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + error_report("error creating device tree: %s: %s", \ #exp, fdt_strerror(ret)); \ exit(1); \ } \ From 3654fa95bc29e72c2eef22f26eb621af1f86feec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 2 Aug 2016 19:38:01 +0200 Subject: [PATCH 54/64] hw/ppc: add a ppc_create_page_sizes_prop() helper routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The exact same routine will be used in PowerNV. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/Makefile.objs | 2 +- hw/ppc/fdt.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr.c | 36 +------------------------------- include/hw/ppc/fdt.h | 5 +++++ 4 files changed, 56 insertions(+), 36 deletions(-) create mode 100644 hw/ppc/fdt.c diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 91a3420f47..99a0d4e581 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -1,5 +1,5 @@ # shared objects -obj-y += ppc.o ppc_booke.o +obj-y += ppc.o ppc_booke.o fdt.o # IBM pSeries (sPAPR) obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o diff --git a/hw/ppc/fdt.c b/hw/ppc/fdt.c new file mode 100644 index 0000000000..e67d60d03c --- /dev/null +++ b/hw/ppc/fdt.c @@ -0,0 +1,49 @@ +/* + * QEMU PowerPC helper routines for the device tree. + * + * Copyright (C) 2016 IBM Corp. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "target-ppc/cpu.h" + +#include "hw/ppc/fdt.h" + +#if defined(TARGET_PPC64) +size_t ppc_create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, + size_t maxsize) +{ + size_t maxcells = maxsize / sizeof(uint32_t); + int i, j, count; + uint32_t *p = prop; + + for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) { + struct ppc_one_seg_page_size *sps = &env->sps.sps[i]; + + if (!sps->page_shift) { + break; + } + for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) { + if (sps->enc[count].page_shift == 0) { + break; + } + } + if ((p - prop) >= (maxcells - 3 - count * 2)) { + break; + } + *(p++) = cpu_to_be32(sps->page_shift); + *(p++) = cpu_to_be32(sps->slb_enc); + *(p++) = cpu_to_be32(count); + for (j = 0; j < count; j++) { + *(p++) = cpu_to_be32(sps->enc[j].page_shift); + *(p++) = cpu_to_be32(sps->enc[j].pte_enc); + } + } + + return (p - prop) * sizeof(uint32_t); +} +#endif diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 7ec27511f5..ca77bb0dea 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -250,40 +250,6 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr) return ret; } - -static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, - size_t maxsize) -{ - size_t maxcells = maxsize / sizeof(uint32_t); - int i, j, count; - uint32_t *p = prop; - - for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) { - struct ppc_one_seg_page_size *sps = &env->sps.sps[i]; - - if (!sps->page_shift) { - break; - } - for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) { - if (sps->enc[count].page_shift == 0) { - break; - } - } - if ((p - prop) >= (maxcells - 3 - count * 2)) { - break; - } - *(p++) = cpu_to_be32(sps->page_shift); - *(p++) = cpu_to_be32(sps->slb_enc); - *(p++) = cpu_to_be32(count); - for (j = 0; j < count; j++) { - *(p++) = cpu_to_be32(sps->enc[j].page_shift); - *(p++) = cpu_to_be32(sps->enc[j].pte_enc); - } - } - - return (p - prop) * sizeof(uint32_t); -} - static hwaddr spapr_node0_size(void) { MachineState *machine = MACHINE(qdev_get_machine()); @@ -689,7 +655,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); } - page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop, + page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop, sizeof(page_sizes_prop)); if (page_sizes_prop_size) { _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes", diff --git a/include/hw/ppc/fdt.h b/include/hw/ppc/fdt.h index 2e5c61af14..2c68d1616f 100644 --- a/include/hw/ppc/fdt.h +++ b/include/hw/ppc/fdt.h @@ -12,6 +12,8 @@ #include "qemu/error-report.h" +typedef struct CPUPPCState CPUPPCState; + #define _FDT(exp) \ do { \ int ret = (exp); \ @@ -22,4 +24,7 @@ } \ } while (0) +size_t ppc_create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, + size_t maxsize); + #endif /* PPC_FDT_H */ From dd2fa4f72d1ce44ce1635fe3a744bd47d8f2ab05 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 2 Aug 2016 19:22:43 +1000 Subject: [PATCH 55/64] ppc: Fix macio ESCC legacy mapping The current mapping, while correct for the base ports (which is all the driver uses these days), is wrong for the extended registers. I suspect the bugs come from incorrect tables in the CHRP IO Ref document, I have verified the new values here match Apple's MacTech.pdf. Note: Nothing that I know of actually uses these registers so it's not a huge deal, but this patch has the added advantage of adding comments to document what the registers are. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- hw/misc/macio/macio.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index be03926b96..5d57f45dc6 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -89,22 +89,16 @@ static void macio_escc_legacy_setup(MacIOState *macio_state) MemoryRegion *bar = &macio_state->bar; int i; static const int maps[] = { - 0x00, 0x00, - 0x02, 0x20, - 0x04, 0x10, - 0x06, 0x30, - 0x08, 0x40, - 0x0A, 0x50, - 0x60, 0x60, - 0x70, 0x70, - 0x80, 0x70, - 0x90, 0x80, - 0xA0, 0x90, - 0xB0, 0xA0, - 0xC0, 0xB0, - 0xD0, 0xC0, - 0xE0, 0xD0, - 0xF0, 0xE0, + 0x00, 0x00, /* Command B */ + 0x02, 0x20, /* Command A */ + 0x04, 0x10, /* Data B */ + 0x06, 0x30, /* Data A */ + 0x08, 0x40, /* Enhancement B */ + 0x0A, 0x50, /* Enhancement A */ + 0x80, 0x80, /* Recovery count */ + 0x90, 0x90, /* Start A */ + 0xa0, 0xa0, /* Start B */ + 0xb0, 0xb0, /* Detect AB */ }; memory_region_init(escc_legacy, OBJECT(macio_state), "escc-legacy", 256); From ba4a8df83f474be1ba02510f960e5224f29d229c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 3 Aug 2016 17:55:23 +1000 Subject: [PATCH 56/64] ppc: Fix catching some segfaults in user mode The usermode "translate" code generates an error code value that has the "is_write" bit set, which causes our switch/case to miss and display "Invalid segfault errno" and a spurrious second state dump. Fix it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- linux-user/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-user/main.c b/linux-user/main.c index d112834644..32070a4a0f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1656,6 +1656,7 @@ void cpu_loop(CPUPPCState *env) /* XXX: check this. Seems bugged */ switch (env->error_code & 0xFF000000) { case 0x40000000: + case 0x42000000: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; From 4f5d326046fa522010c0a66f1bcaac9068253085 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 3 Aug 2016 21:44:08 +1000 Subject: [PATCH 57/64] ppc: Stop dumping state on all exceptions in linux-user Other archs don't do it, some programs catch signals just fine and those dumps just clutter the output. Keep the dumps for cases that aren't supposed to happen such as unknown codes. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- linux-user/main.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 32070a4a0f..6004ece152 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1651,8 +1651,6 @@ void cpu_loop(CPUPPCState *env) "Aborting\n"); break; case POWERPC_EXCP_DSI: /* Data storage exception */ - EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n", - env->spr[SPR_DAR]); /* XXX: check this. Seems bugged */ switch (env->error_code & 0xFF000000) { case 0x40000000: @@ -1684,8 +1682,6 @@ void cpu_loop(CPUPPCState *env) queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_ISI: /* Instruction storage exception */ - EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx - "\n", env->spr[SPR_SRR0]); /* XXX: check this */ switch (env->error_code & 0xFF000000) { case 0x40000000: @@ -1716,7 +1712,6 @@ void cpu_loop(CPUPPCState *env) "Aborting\n"); break; case POWERPC_EXCP_ALIGN: /* Alignment exception */ - EXCP_DUMP(env, "Unaligned memory access\n"); /* XXX: check this */ info.si_signo = TARGET_SIGBUS; info.si_errno = 0; @@ -1729,7 +1724,6 @@ void cpu_loop(CPUPPCState *env) /* XXX: check this */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: - EXCP_DUMP(env, "Floating point program exception\n"); info.si_signo = TARGET_SIGFPE; info.si_errno = 0; switch (env->error_code & 0xF) { @@ -1765,7 +1759,6 @@ void cpu_loop(CPUPPCState *env) } break; case POWERPC_EXCP_INVAL: - EXCP_DUMP(env, "Invalid instruction\n"); info.si_signo = TARGET_SIGILL; info.si_errno = 0; switch (env->error_code & 0xF) { @@ -1789,7 +1782,6 @@ void cpu_loop(CPUPPCState *env) } break; case POWERPC_EXCP_PRIV: - EXCP_DUMP(env, "Privilege violation\n"); info.si_signo = TARGET_SIGILL; info.si_errno = 0; switch (env->error_code & 0xF) { @@ -1819,7 +1811,6 @@ void cpu_loop(CPUPPCState *env) queue_signal(env, info.si_signo, &info); break; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ - EXCP_DUMP(env, "No floating point allowed\n"); info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; @@ -1831,7 +1822,6 @@ void cpu_loop(CPUPPCState *env) "Aborting\n"); break; case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ - EXCP_DUMP(env, "No APU instruction allowed\n"); info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; @@ -1859,7 +1849,6 @@ void cpu_loop(CPUPPCState *env) "Aborting\n"); break; case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */ - EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n"); info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; @@ -1923,7 +1912,6 @@ void cpu_loop(CPUPPCState *env) "while in user mode. Aborting\n"); break; case POWERPC_EXCP_VPU: /* Vector unavailable exception */ - EXCP_DUMP(env, "No Altivec instructions allowed\n"); info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; From accc60c47c9b57f49865d1bed6df3d3085fec81d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 31 Jul 2016 15:13:09 +1000 Subject: [PATCH 58/64] ppc: Don't generate dead code on unconditional branches We are always generating the "else" case of the condition even when generating an unconditional branch that will never hit it. Signed-off-by: Benjamin Herrenschmidt Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 0a5a3e21f0..618334ae51 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3480,8 +3480,10 @@ static inline void gen_bcond(DisasContext *ctx, int type) } else { gen_goto_tb(ctx, 0, li); } - gen_set_label(l1); - gen_goto_tb(ctx, 1, ctx->nip); + if ((bo & 0x14) != 0x14) { + gen_set_label(l1); + gen_goto_tb(ctx, 1, ctx->nip); + } } else { if (NARROW_MODE(ctx)) { tcg_gen_andi_tl(cpu_nip, target, (uint32_t)~3); @@ -3489,9 +3491,11 @@ static inline void gen_bcond(DisasContext *ctx, int type) tcg_gen_andi_tl(cpu_nip, target, ~3); } tcg_gen_exit_tb(0); - gen_set_label(l1); - gen_update_nip(ctx, ctx->nip); - tcg_gen_exit_tb(0); + if ((bo & 0x14) != 0x14) { + gen_set_label(l1); + gen_update_nip(ctx, ctx->nip); + tcg_gen_exit_tb(0); + } } if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) { tcg_temp_free(target); From d0f6ced17fb04b6a0cbeb32e5950a3df8b3c4b5d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 31 Jul 2016 15:13:10 +1000 Subject: [PATCH 59/64] ppc: Improve flags for helpers loading/writing the time facilities Those helpers never load from or store to the TCG tracked environment, not do they generate synchronous exceptions (they might generate an asynchronous interrupt but that's not an issue here). So we can make them all use TCG_CALL_NO_RWG Signed-off-by: Benjamin Herrenschmidt Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 8eada2f889..b0c1db9661 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -595,35 +595,35 @@ DEF_HELPER_2(load_dump_spr, void, env, i32) DEF_HELPER_2(store_dump_spr, void, env, i32) DEF_HELPER_4(fscr_facility_check, void, env, i32, i32, i32) DEF_HELPER_4(msr_facility_check, void, env, i32, i32, i32) -DEF_HELPER_1(load_tbl, tl, env) -DEF_HELPER_1(load_tbu, tl, env) -DEF_HELPER_1(load_atbl, tl, env) -DEF_HELPER_1(load_atbu, tl, env) -DEF_HELPER_1(load_601_rtcl, tl, env) -DEF_HELPER_1(load_601_rtcu, tl, env) +DEF_HELPER_FLAGS_1(load_tbl, TCG_CALL_NO_RWG, tl, env) +DEF_HELPER_FLAGS_1(load_tbu, TCG_CALL_NO_RWG, tl, env) +DEF_HELPER_FLAGS_1(load_atbl, TCG_CALL_NO_RWG, tl, env) +DEF_HELPER_FLAGS_1(load_atbu, TCG_CALL_NO_RWG, tl, env) +DEF_HELPER_FLAGS_1(load_601_rtcl, TCG_CALL_NO_RWG, tl, env) +DEF_HELPER_FLAGS_1(load_601_rtcu, TCG_CALL_NO_RWG, tl, env) #if !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) -DEF_HELPER_1(load_purr, tl, env) +DEF_HELPER_FLAGS_1(load_purr, TCG_CALL_NO_RWG, tl, env) #endif DEF_HELPER_2(store_sdr1, void, env, tl) -DEF_HELPER_2(store_tbl, void, env, tl) -DEF_HELPER_2(store_tbu, void, env, tl) -DEF_HELPER_2(store_atbl, void, env, tl) -DEF_HELPER_2(store_atbu, void, env, tl) -DEF_HELPER_2(store_601_rtcl, void, env, tl) -DEF_HELPER_2(store_601_rtcu, void, env, tl) -DEF_HELPER_1(load_decr, tl, env) -DEF_HELPER_2(store_decr, void, env, tl) -DEF_HELPER_1(load_hdecr, tl, env) -DEF_HELPER_2(store_hdecr, void, env, tl) +DEF_HELPER_FLAGS_2(store_tbl, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_FLAGS_2(store_tbu, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_FLAGS_2(store_atbl, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_FLAGS_2(store_atbu, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_FLAGS_2(store_601_rtcl, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_FLAGS_2(store_601_rtcu, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_FLAGS_1(load_decr, TCG_CALL_NO_RWG, tl, env) +DEF_HELPER_FLAGS_2(store_decr, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_FLAGS_1(load_hdecr, TCG_CALL_NO_RWG, tl, env) +DEF_HELPER_FLAGS_2(store_hdecr, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_2(store_hid0_601, void, env, tl) DEF_HELPER_3(store_403_pbr, void, env, i32, tl) -DEF_HELPER_1(load_40x_pit, tl, env) -DEF_HELPER_2(store_40x_pit, void, env, tl) +DEF_HELPER_FLAGS_1(load_40x_pit, TCG_CALL_NO_RWG, tl, env) +DEF_HELPER_FLAGS_2(store_40x_pit, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_2(store_40x_dbcr0, void, env, tl) DEF_HELPER_2(store_40x_sler, void, env, tl) -DEF_HELPER_2(store_booke_tcr, void, env, tl) -DEF_HELPER_2(store_booke_tsr, void, env, tl) +DEF_HELPER_FLAGS_2(store_booke_tcr, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_FLAGS_2(store_booke_tsr, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_3(store_ibatl, void, env, i32, tl) DEF_HELPER_3(store_ibatu, void, env, i32, tl) DEF_HELPER_3(store_dbatl, void, env, i32, tl) From 76a3d2f750476e77a3287937bf4189e527514dc1 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 31 Jul 2016 15:13:11 +1000 Subject: [PATCH 60/64] ppc: Improve the exception helpers flags They generate exceptions, but they don't update the environment Signed-off-by: Benjamin Herrenschmidt Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index b0c1db9661..d83086e14a 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -1,5 +1,5 @@ -DEF_HELPER_3(raise_exception_err, void, env, i32, i32) -DEF_HELPER_2(raise_exception, void, env, i32) +DEF_HELPER_FLAGS_3(raise_exception_err, TCG_CALL_NO_WG, void, env, i32, i32) +DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, void, env, i32) DEF_HELPER_4(tw, void, env, tl, tl, i32) #if defined(TARGET_PPC64) DEF_HELPER_4(td, void, env, tl, tl, i32) From a007b19b37d571a01bc8a4458537345402eb01c0 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 31 Jul 2016 15:13:12 +1000 Subject: [PATCH 61/64] ppc: Improve a few more helper flags Mostly turn "store" type of helpers into TCG_CALL_NO_WG because they can take exceptions. Also fixup_thrm doesn't read nor write the tracked environment. Signed-off-by: Benjamin Herrenschmidt Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index d83086e14a..dcf3f950b6 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -1,8 +1,8 @@ DEF_HELPER_FLAGS_3(raise_exception_err, TCG_CALL_NO_WG, void, env, i32, i32) DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, void, env, i32) -DEF_HELPER_4(tw, void, env, tl, tl, i32) +DEF_HELPER_FLAGS_4(tw, TCG_CALL_NO_WG, void, env, tl, tl, i32) #if defined(TARGET_PPC64) -DEF_HELPER_4(td, void, env, tl, tl, i32) +DEF_HELPER_FLAGS_4(td, TCG_CALL_NO_WG, void, env, tl, tl, i32) #endif #if !defined(CONFIG_USER_ONLY) DEF_HELPER_2(store_msr, void, env, tl) @@ -22,12 +22,12 @@ DEF_HELPER_1(check_tlb_flush, void, env) #endif DEF_HELPER_3(lmw, void, env, tl, i32) -DEF_HELPER_3(stmw, void, env, tl, i32) +DEF_HELPER_FLAGS_3(stmw, TCG_CALL_NO_WG, void, env, tl, i32) DEF_HELPER_4(lsw, void, env, tl, i32, i32) DEF_HELPER_5(lswx, void, env, tl, i32, i32, i32) -DEF_HELPER_4(stsw, void, env, tl, i32, i32) -DEF_HELPER_3(dcbz, void, env, tl, i32) -DEF_HELPER_2(icbi, void, env, tl) +DEF_HELPER_FLAGS_4(stsw, TCG_CALL_NO_WG, void, env, tl, i32, i32) +DEF_HELPER_FLAGS_3(dcbz, TCG_CALL_NO_WG, void, env, tl, i32) +DEF_HELPER_FLAGS_2(icbi, TCG_CALL_NO_WG, void, env, tl) DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32) #if defined(TARGET_PPC64) @@ -690,4 +690,4 @@ DEF_HELPER_4(dscli, void, env, fprp, fprp, i32) DEF_HELPER_4(dscliq, void, env, fprp, fprp, i32) DEF_HELPER_1(tbegin, void, env) -DEF_HELPER_1(fixup_thrm, void, env) +DEF_HELPER_FLAGS_1(fixup_thrm, TCG_CALL_NO_RWG, void, env) From 32f5f50dade3def9e51fdff505f79c67809fe647 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 1 Sep 2016 10:10:49 +0200 Subject: [PATCH 62/64] spapr: implement H_CHANGE_LOGICAL_LAN_MAC h_call Since kernel v4.0, linux uses H_CHANGE_LOGICAL_LAN_MAC to change lively the MAC address of an ibmveth interface. As QEMU doesn't implement this h_call, we can't change anymore the MAC address of an spapr-vlan interface. Signed-off-by: Laurent Vivier Signed-off-by: David Gibson --- hw/net/spapr_llan.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index b273eda933..4bb95a51dd 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -106,6 +106,7 @@ typedef struct VIOsPAPRVLANDevice { VIOsPAPRDevice sdev; NICConf nicconf; NICState *nic; + MACAddr perm_mac; bool isopen; hwaddr buf_list; uint32_t add_buf_ptr, use_buf_ptr, rx_bufs; @@ -316,6 +317,10 @@ static void spapr_vlan_reset(VIOsPAPRDevice *sdev) spapr_vlan_reset_rx_pool(dev->rx_pool[i]); } } + + memcpy(&dev->nicconf.macaddr.a, &dev->perm_mac.a, + sizeof(dev->nicconf.macaddr.a)); + qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a); } static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp) @@ -324,6 +329,8 @@ static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp) qemu_macaddr_default_if_unset(&dev->nicconf.macaddr); + memcpy(&dev->perm_mac.a, &dev->nicconf.macaddr.a, sizeof(dev->perm_mac.a)); + dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf, object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev); qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a); @@ -756,6 +763,27 @@ static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPRMachineState *spapr, return H_SUCCESS; } +static target_ulong h_change_logical_lan_mac(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong macaddr = args[1]; + VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev); + int i; + + for (i = 0; i < ETH_ALEN; i++) { + dev->nicconf.macaddr.a[ETH_ALEN - i - 1] = macaddr & 0xff; + macaddr >>= 8; + } + + qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a); + + return H_SUCCESS; +} + static Property spapr_vlan_properties[] = { DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev), DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf), @@ -854,6 +882,8 @@ static void spapr_vlan_register_types(void) spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER, h_add_logical_lan_buffer); spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl); + spapr_register_hypercall(H_CHANGE_LOGICAL_LAN_MAC, + h_change_logical_lan_mac); type_register_static(&spapr_vlan_info); } From 29531542bc92603a198d50412e1142b9f0fb0a73 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Sat, 3 Sep 2016 11:57:50 +0200 Subject: [PATCH 63/64] tests: Resort check-qtest entries in Makefile.include The rather random list of check-qtest-xxx entries caused some confusion in the past, where to use "=" and where to use "+=" (see commits 0ccac16f59462b8e2b9afbc1 and 1f5c1cfbaec0792cd2e5da for example). Sorting the check-qtest-xxx entries by architecure instead and using some empty lines inbetween should help to ease this situation a little bit, so that it is hopefully now obvious that new tests should be added with "+=" instead of "=". While we are at it, this patch also comments out two of the "gcov-files-..." lines since the corresponding m48t59-test is disabled for sparc and sparc64, too. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- tests/Makefile.include | 44 +++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 03382b5fe7..6f457cc698 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -241,37 +241,49 @@ check-qtest-i386-y += tests/postcopy-test$(EXESUF) check-qtest-x86_64-y += $(check-qtest-i386-y) gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)) + check-qtest-mips-y = tests/endianness-test$(EXESUF) + check-qtest-mips64-y = tests/endianness-test$(EXESUF) + check-qtest-mips64el-y = tests/endianness-test$(EXESUF) + check-qtest-ppc-y = tests/endianness-test$(EXESUF) -check-qtest-ppc64-y = tests/endianness-test$(EXESUF) +check-qtest-ppc-y += tests/boot-order-test$(EXESUF) +check-qtest-ppc-y += tests/prom-env-test$(EXESUF) +check-qtest-ppc-y += tests/drive_del-test$(EXESUF) + +check-qtest-ppc64-y = tests/spapr-phb-test$(EXESUF) +gcov-files-ppc64-y = ppc64-softmmu/hw/ppc/spapr_pci.c +check-qtest-ppc64-y += tests/endianness-test$(EXESUF) +check-qtest-ppc64-y += tests/boot-order-test$(EXESUF) +check-qtest-ppc64-y += tests/prom-env-test$(EXESUF) +check-qtest-ppc64-y += tests/drive_del-test$(EXESUF) +check-qtest-ppc64-y += tests/postcopy-test$(EXESUF) + check-qtest-sh4-y = tests/endianness-test$(EXESUF) + check-qtest-sh4eb-y = tests/endianness-test$(EXESUF) + +check-qtest-sparc-y = tests/prom-env-test$(EXESUF) +#check-qtest-sparc-y += tests/m48t59-test$(EXESUF) +#gcov-files-sparc-y = hw/timer/m48t59.c + check-qtest-sparc64-y = tests/endianness-test$(EXESUF) -#check-qtest-sparc-y = tests/m48t59-test$(EXESUF) #check-qtest-sparc64-y += tests/m48t59-test$(EXESUF) -gcov-files-sparc-y += hw/timer/m48t59.c -gcov-files-sparc64-y += hw/timer/m48t59.c +#gcov-files-sparc64-y += hw/timer/m48t59.c +#Disabled for now, triggers a TCG bug on 32-bit hosts +#check-qtest-sparc64-y += tests/prom-env-test$(EXESUF) + check-qtest-arm-y = tests/tmp105-test$(EXESUF) check-qtest-arm-y += tests/ds1338-test$(EXESUF) gcov-files-arm-y += hw/misc/tmp105.c check-qtest-arm-y += tests/virtio-blk-test$(EXESUF) gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c -check-qtest-ppc-y += tests/boot-order-test$(EXESUF) -check-qtest-ppc64-y += tests/boot-order-test$(EXESUF) -check-qtest-ppc-y += tests/drive_del-test$(EXESUF) -check-qtest-ppc64-y += tests/drive_del-test$(EXESUF) -check-qtest-ppc64-y += tests/spapr-phb-test$(EXESUF) -gcov-files-ppc64-y += ppc64-softmmu/hw/ppc/spapr_pci.c -check-qtest-ppc-y += tests/prom-env-test$(EXESUF) -check-qtest-ppc64-y += tests/prom-env-test$(EXESUF) -check-qtest-sparc-y += tests/prom-env-test$(EXESUF) -#Disabled for now, triggers a TCG bug on 32-bit hosts -#check-qtest-sparc64-y += tests/prom-env-test$(EXESUF) + check-qtest-microblazeel-y = $(check-qtest-microblaze-y) + check-qtest-xtensaeb-y = $(check-qtest-xtensa-y) -check-qtest-ppc64-y += tests/postcopy-test$(EXESUF) check-qtest-generic-y += tests/qom-test$(EXESUF) From d2ab58ffc927c00e88f53f9b853b015a76fa1bd2 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Sat, 3 Sep 2016 11:57:51 +0200 Subject: [PATCH 64/64] tests: Check serial output of firmware boot of some machines Some of the machines that we have got a firmware image for write some output to the serial console while booting up. We can use this output to make sure that the machine is basically working, so this adds a test that checks the output of these machines for some well-known "magic" strings. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- tests/Makefile.include | 8 +++ tests/boot-serial-test.c | 110 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 tests/boot-serial-test.c diff --git a/tests/Makefile.include b/tests/Makefile.include index 6f457cc698..e3a3266370 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -195,6 +195,7 @@ check-qtest-i386-y += tests/hd-geo-test$(EXESUF) gcov-files-i386-y += hw/block/hd-geometry.c check-qtest-i386-y += tests/boot-order-test$(EXESUF) check-qtest-i386-y += tests/bios-tables-test$(EXESUF) +check-qtest-i386-y += tests/boot-serial-test$(EXESUF) check-qtest-i386-y += tests/pxe-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-i386-y += tests/ipmi-kcs-test$(EXESUF) @@ -242,6 +243,8 @@ check-qtest-x86_64-y += $(check-qtest-i386-y) gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)) +check-qtest-alpha-y = tests/boot-serial-test$(EXESUF) + check-qtest-mips-y = tests/endianness-test$(EXESUF) check-qtest-mips64-y = tests/endianness-test$(EXESUF) @@ -252,6 +255,7 @@ check-qtest-ppc-y = tests/endianness-test$(EXESUF) check-qtest-ppc-y += tests/boot-order-test$(EXESUF) check-qtest-ppc-y += tests/prom-env-test$(EXESUF) check-qtest-ppc-y += tests/drive_del-test$(EXESUF) +check-qtest-ppc-y += tests/boot-serial-test$(EXESUF) check-qtest-ppc64-y = tests/spapr-phb-test$(EXESUF) gcov-files-ppc64-y = ppc64-softmmu/hw/ppc/spapr_pci.c @@ -260,6 +264,7 @@ check-qtest-ppc64-y += tests/boot-order-test$(EXESUF) check-qtest-ppc64-y += tests/prom-env-test$(EXESUF) check-qtest-ppc64-y += tests/drive_del-test$(EXESUF) check-qtest-ppc64-y += tests/postcopy-test$(EXESUF) +check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF) check-qtest-sh4-y = tests/endianness-test$(EXESUF) @@ -285,6 +290,8 @@ check-qtest-microblazeel-y = $(check-qtest-microblaze-y) check-qtest-xtensaeb-y = $(check-qtest-xtensa-y) +check-qtest-s390x-y = tests/boot-serial-test$(EXESUF) + check-qtest-generic-y += tests/qom-test$(EXESUF) qapi-schema += alternate-any.json @@ -590,6 +597,7 @@ tests/ipmi-kcs-test$(EXESUF): tests/ipmi-kcs-test.o tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) +tests/boot-serial-test$(EXESUF): tests/boot-serial-test.o $(libqos-obj-y) tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ tests/boot-sector.o $(libqos-obj-y) tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y) diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c new file mode 100644 index 0000000000..d98c564a35 --- /dev/null +++ b/tests/boot-serial-test.c @@ -0,0 +1,110 @@ +/* + * Test serial output of some machines. + * + * Copyright 2016 Thomas Huth, Red Hat Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 + * or later. See the COPYING file in the top-level directory. + * + * This test is used to check that the serial output of the firmware + * (that we provide for some machines) contains an expected string. + * Thus we check that the firmware still boots at least to a certain + * point and so we know that the machine is not completely broken. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" + +typedef struct testdef { + const char *arch; /* Target architecture */ + const char *machine; /* Name of the machine */ + const char *extra; /* Additional parameters */ + const char *expect; /* Expected string in the serial output */ +} testdef_t; + +static testdef_t tests[] = { + { "alpha", "clipper", "", "PCI:" }, + { "ppc", "ppce500", "", "U-Boot" }, + { "ppc", "prep", "", "Open Hack'Ware BIOS" }, + { "ppc64", "ppce500", "", "U-Boot" }, + { "ppc64", "prep", "", "Open Hack'Ware BIOS" }, + { "ppc64", "pseries", "", "Open Firmware" }, + { "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" }, + { "i386", "pc", "-device sga", "SGABIOS" }, + { "i386", "q35", "-device sga", "SGABIOS" }, + { "x86_64", "isapc", "-cpu qemu32 -device sga", "SGABIOS" }, + { "x86_64", "q35", "-device sga", "SGABIOS" }, + { "s390x", "s390-ccw-virtio", + "-nodefaults -device sclpconsole,chardev=serial0", "virtio device" }, + { NULL } +}; + +static void check_guest_output(const testdef_t *test, int fd) +{ + bool output_ok = false; + int i, nbr, pos = 0; + char ch; + + /* Poll serial output... Wait at most 60 seconds */ + for (i = 0; i < 6000; ++i) { + while ((nbr = read(fd, &ch, 1)) == 1) { + if (ch == test->expect[pos]) { + pos += 1; + if (test->expect[pos] == '\0') { + /* We've reached the end of the expected string! */ + output_ok = true; + goto done; + } + } else { + pos = 0; + } + } + g_assert(nbr >= 0); + g_usleep(10000); + } + +done: + g_assert(output_ok); +} + +static void test_machine(const void *data) +{ + const testdef_t *test = data; + char *args; + char tmpname[] = "/tmp/qtest-boot-serial-XXXXXX"; + int fd; + + fd = mkstemp(tmpname); + g_assert(fd != -1); + + args = g_strdup_printf("-M %s,accel=tcg -chardev file,id=serial0,path=%s" + " -serial chardev:serial0 %s", test->machine, + tmpname, test->extra); + + qtest_start(args); + unlink(tmpname); + + check_guest_output(test, fd); + qtest_quit(global_qtest); + + g_free(args); + close(fd); +} + +int main(int argc, char *argv[]) +{ + const char *arch = qtest_get_arch(); + int i; + + g_test_init(&argc, &argv, NULL); + + for (i = 0; tests[i].arch != NULL; i++) { + if (strcmp(arch, tests[i].arch) == 0) { + char *name = g_strdup_printf("boot-serial/%s", tests[i].machine); + qtest_add_data_func(name, &tests[i], test_machine); + g_free(name); + } + } + + return g_test_run(); +}