From c24ba3d0a34f68ad2c6bf1a15bc43770005f6cc0 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 19 Dec 2018 17:35:41 +0100 Subject: [PATCH 01/29] spapr: Add H-Call H_HOME_NODE_ASSOCIATIVITY H_HOME_NODE_ASSOCIATIVITY H-Call returns the associativity domain designation associated with the identifier input parameter This fixes a crash when we try to hotplug a CPU in memory-less and CPU-less numa node. In this case, the kernel tries to online the node, but without the information provided by this h-call, the node id, it cannot and the CPU is started while the node is not onlined. It also removes the warning message from the kernel: VPHN is not supported. Disabling polling.. Signed-off-by: Laurent Vivier Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr.c | 1 + hw/ppc/spapr_hcall.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 1 + 3 files changed, 42 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 5671608cea..5fba04e7b2 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1048,6 +1048,7 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt) add_str(hypertas, "hcall-sprg0"); add_str(hypertas, "hcall-copy"); add_str(hypertas, "hcall-debug"); + add_str(hypertas, "hcall-vphn"); add_str(qemu_hypertas, "hcall-memop1"); if (!kvm_enabled() || kvmppc_spapr_use_multitce()) { diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index ae913d070f..f131c7e04c 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1663,6 +1663,42 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, return H_SUCCESS; } +static target_ulong h_home_node_associativity(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong procno = args[1]; + PowerPCCPU *tcpu; + int idx; + + /* only support procno from H_REGISTER_VPA */ + if (flags != 0x1) { + return H_FUNCTION; + } + + tcpu = spapr_find_cpu(procno); + if (tcpu == NULL) { + return H_P2; + } + + /* sequence is the same as in the "ibm,associativity" property */ + + idx = 0; +#define ASSOCIATIVITY(a, b) (((uint64_t)(a) << 32) | \ + ((uint64_t)(b) & 0xffffffff)) + args[idx++] = ASSOCIATIVITY(0, 0); + args[idx++] = ASSOCIATIVITY(0, tcpu->node_id); + args[idx++] = ASSOCIATIVITY(procno, -1); + for ( ; idx < 6; idx++) { + args[idx] = -1; + } +#undef ASSOCIATIVITY + + return H_SUCCESS; +} + static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, @@ -1822,6 +1858,10 @@ static void hypercall_register_types(void) /* ibm,client-architecture-support support */ spapr_register_hypercall(KVMPPC_H_CAS, h_client_architecture_support); + + /* Virtual Processor Home Node */ + spapr_register_hypercall(H_HOME_NODE_ASSOCIATIVITY, + h_home_node_associativity); } type_init(hypercall_register_types) diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 2c77a8ba88..eb04300d3b 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -444,6 +444,7 @@ struct sPAPRMachineState { #define H_GET_EM_PARMS 0x2B8 #define H_SET_MPP 0x2D0 #define H_GET_MPP 0x2D4 +#define H_HOME_NODE_ASSOCIATIVITY 0x2EC #define H_XIRR_X 0x2FC #define H_RANDOM 0x300 #define H_SET_MODE 0x31C From fea35ca4b8e68b4fae5df7a13d8f300d9abfb40a Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 21 Dec 2018 01:34:48 +0100 Subject: [PATCH 02/29] ppc/spapr: Receive and store device tree blob from SLOF SLOF receives a device tree and updates it with various properties before switching to the guest kernel and QEMU is not aware of any changes made by SLOF. Since there is no real RTAS (QEMU implements it), it makes sense to pass the SLOF final device tree to QEMU to let it implement RTAS related tasks better, such as PCI host bus adapter hotplug. Specifially, now QEMU can find out the actual XICS phandle (for PHB hotplug) and the RTAS linux,rtas-entry/base properties (for firmware assisted NMI - FWNMI). This stores the initial DT blob in the sPAPR machine and replaces it in the KVMPPC_H_UPDATE_DT (new private hypercall) handler. This adds an @update_dt_enabled machine property to allow backward migration. SLOF already has a hypercall since https://github.com/aik/SLOF/commit/e6fc84652c9c0073f9183 This makes use of the new fdt_check_full() helper. In order to allow the configure script to pick the correct DTC version, this adjusts the DTC presense test. Signed-off-by: Alexey Kardashevskiy Reviewed-by: Greg Kurz Signed-off-by: David Gibson Signed-off-by: Greg Kurz Signed-off-by: David Gibson --- configure | 2 +- hw/ppc/spapr.c | 43 +++++++++++++++++++++++++++++++++++++++++- hw/ppc/spapr_hcall.c | 42 +++++++++++++++++++++++++++++++++++++++++ hw/ppc/trace-events | 3 +++ include/hw/ppc/spapr.h | 7 ++++++- 5 files changed, 94 insertions(+), 3 deletions(-) diff --git a/configure b/configure index b9f34afc9e..8049b71eef 100755 --- a/configure +++ b/configure @@ -3939,7 +3939,7 @@ if test "$fdt" != "no" ; then cat > $TMPC << EOF #include #include -int main(void) { fdt_first_subnode(0, 0); return 0; } +int main(void) { fdt_check_full(NULL, 0); return 0; } EOF if compile_prog "" "$fdt_libs" ; then # system DTC is good - use it diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 5fba04e7b2..7e61f1e5ff 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1669,7 +1669,10 @@ static void spapr_machine_reset(void) /* Load the fdt */ qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt)); cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); - g_free(fdt); + g_free(spapr->fdt_blob); + spapr->fdt_size = fdt_totalsize(fdt); + spapr->fdt_initial_size = spapr->fdt_size; + spapr->fdt_blob = fdt; /* Set up the entry state */ spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr); @@ -1920,6 +1923,39 @@ static const VMStateDescription vmstate_spapr_irq_map = { }, }; +static bool spapr_dtb_needed(void *opaque) +{ + sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque); + + return smc->update_dt_enabled; +} + +static int spapr_dtb_pre_load(void *opaque) +{ + sPAPRMachineState *spapr = (sPAPRMachineState *)opaque; + + g_free(spapr->fdt_blob); + spapr->fdt_blob = NULL; + spapr->fdt_size = 0; + + return 0; +} + +static const VMStateDescription vmstate_spapr_dtb = { + .name = "spapr_dtb", + .version_id = 1, + .minimum_version_id = 1, + .needed = spapr_dtb_needed, + .pre_load = spapr_dtb_pre_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(fdt_initial_size, sPAPRMachineState), + VMSTATE_UINT32(fdt_size, sPAPRMachineState), + VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, sPAPRMachineState, 0, NULL, + fdt_size), + VMSTATE_END_OF_LIST() + }, +}; + static const VMStateDescription vmstate_spapr = { .name = "spapr", .version_id = 3, @@ -1949,6 +1985,7 @@ static const VMStateDescription vmstate_spapr = { &vmstate_spapr_cap_ibs, &vmstate_spapr_irq_map, &vmstate_spapr_cap_nested_kvm_hv, + &vmstate_spapr_dtb, NULL } }; @@ -3931,6 +3968,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) hc->unplug = spapr_machine_device_unplug; smc->dr_lmb_enabled = true; + smc->update_dt_enabled = true; mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0"); mc->has_hotpluggable_cpus = true; smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED; @@ -4023,9 +4061,12 @@ DEFINE_SPAPR_MACHINE(4_0, "4.0", true); */ static void spapr_machine_3_1_class_options(MachineClass *mc) { + sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + spapr_machine_4_0_class_options(mc); compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len); mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0"); + smc->update_dt_enabled = false; } DEFINE_SPAPR_MACHINE(3_1, "3.1", false); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index f131c7e04c..1ae3e6ff5e 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1753,6 +1753,46 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu, args[0] = characteristics; args[1] = behaviour; + return H_SUCCESS; +} + +static target_ulong h_update_dt(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong dt = ppc64_phys_to_real(args[0]); + struct fdt_header hdr = { 0 }; + unsigned cb; + sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + void *fdt; + + cpu_physical_memory_read(dt, &hdr, sizeof(hdr)); + cb = fdt32_to_cpu(hdr.totalsize); + + if (!smc->update_dt_enabled) { + return H_SUCCESS; + } + + /* Check that the fdt did not grow out of proportion */ + if (cb > spapr->fdt_initial_size * 2) { + trace_spapr_update_dt_failed_size(spapr->fdt_initial_size, cb, + fdt32_to_cpu(hdr.magic)); + return H_PARAMETER; + } + + fdt = g_malloc0(cb); + cpu_physical_memory_read(dt, fdt, cb); + + /* Check the fdt consistency */ + if (fdt_check_full(fdt, cb)) { + trace_spapr_update_dt_failed_check(spapr->fdt_initial_size, cb, + fdt32_to_cpu(hdr.magic)); + return H_PARAMETER; + } + + g_free(spapr->fdt_blob); + spapr->fdt_size = cb; + spapr->fdt_blob = fdt; + trace_spapr_update_dt(cb); return H_SUCCESS; } @@ -1859,6 +1899,8 @@ static void hypercall_register_types(void) /* ibm,client-architecture-support support */ spapr_register_hypercall(KVMPPC_H_CAS, h_client_architecture_support); + spapr_register_hypercall(KVMPPC_H_UPDATE_DT, h_update_dt); + /* Virtual Processor Home Node */ spapr_register_hypercall(H_HOME_NODE_ASSOCIATIVITY, h_home_node_associativity); diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index dc5e65aee9..0af155ed32 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -22,6 +22,9 @@ spapr_cas_pvr_try(uint32_t pvr) "0x%x" spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=0x%x, explicit_match=%u, new=0x%x" spapr_h_resize_hpt_prepare(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64 spapr_h_resize_hpt_commit(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64 +spapr_update_dt(unsigned cb) "New blob %u bytes" +spapr_update_dt_failed_size(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x" +spapr_update_dt_failed_check(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x" # hw/ppc/spapr_iommu.c spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=0x%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64 diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index eb04300d3b..fd24e91bd8 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -103,6 +103,7 @@ struct sPAPRMachineClass { /*< public >*/ bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */ + bool update_dt_enabled; /* enable KVMPPC_H_UPDATE_DT */ bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ bool pre_2_10_has_unused_icps; bool legacy_irq_allocation; @@ -139,6 +140,9 @@ struct sPAPRMachineState { int vrma_adjust; ssize_t rtas_size; void *rtas_blob; + uint32_t fdt_size; + uint32_t fdt_initial_size; + void *fdt_blob; long kernel_size; bool kernel_le; uint32_t initrd_base; @@ -481,7 +485,8 @@ struct sPAPRMachineState { #define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1) /* Client Architecture support */ #define KVMPPC_H_CAS (KVMPPC_HCALL_BASE + 0x2) -#define KVMPPC_HCALL_MAX KVMPPC_H_CAS +#define KVMPPC_H_UPDATE_DT (KVMPPC_HCALL_BASE + 0x3) +#define KVMPPC_HCALL_MAX KVMPPC_H_UPDATE_DT typedef struct sPAPRDeviceTreeUpdateHeader { uint32_t version_id; From a0557225fef3efed3a0556254b9adb639c6061c1 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 2 Jan 2019 03:06:38 +0100 Subject: [PATCH 03/29] ppc4xx: Disable debug logging by default Debug logs were left enabled in ppc4xx_devs.c whereas in other files these are normally not enabled. Disable it here as well. Signed-off-by: BALATON Zoltan Signed-off-by: David Gibson --- hw/ppc/ppc4xx_devs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index 8c6f3c9577..9b6e4c60fa 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -32,8 +32,7 @@ #include "exec/address-spaces.h" #include "qemu/error-report.h" -#define DEBUG_UIC - +/*#define DEBUG_UIC*/ #ifdef DEBUG_UIC # define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) From 33c6a8b58e239d8199ff93dba45ceddf413d5f15 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 2 Jan 2019 03:06:38 +0100 Subject: [PATCH 04/29] MAINTAINERS: Add more files to sam460ex The sm501 model belonged to SH before but that seems to be inactive now and latest changes were for sam460ex which is the more active user of this device at the moment so let's adopt sm501 for sam460ex. Also add device tree and firmware sources and binaries. Signed-off-by: BALATON Zoltan Signed-off-by: David Gibson --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0bfd95a4ef..fc0be06756 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1052,8 +1052,14 @@ sam460ex M: BALATON Zoltan L: qemu-ppc@nongnu.org S: Maintained +F: hw/ppc/sam460ex.c +F: hw/ppc/ppc440_pcix.c +F: hw/display/sm501* F: hw/ide/sii3112.c F: hw/timer/m41t80.c +F: pc-bios/canyonlands.dt[sb] +F: pc-bios/u-boot-sam460ex-20100605.bin +F: roms/u-boot-sam460ex SH4 Machines ------------ From ffcd21acb45ade8591e78ca78af3f567a4bb2e9b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 2 Jan 2019 09:14:15 +0000 Subject: [PATCH 05/29] target/ppc: fix typo in SIMM5 extraction helper As the macro name suggests, the argument should be signed and not unsigned. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target/ppc/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/internal.h b/target/ppc/internal.h index a9bcadff42..8b35863549 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -124,7 +124,7 @@ EXTRACT_SHELPER(SIMM, 0, 16); /* 16 bits unsigned immediate value */ EXTRACT_HELPER(UIMM, 0, 16); /* 5 bits signed immediate value */ -EXTRACT_HELPER(SIMM5, 16, 5); +EXTRACT_SHELPER(SIMM5, 16, 5); /* 5 bits signed immediate value */ EXTRACT_HELPER(UIMM5, 16, 5); /* 4 bits unsigned immediate value */ From 4c23c2a538fb8bd78111eb56eb61b001e3b1490f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 2 Jan 2019 09:14:16 +0000 Subject: [PATCH 06/29] target/ppc: switch EXTRACT_HELPER macros over to use sextract32/extract32 These ensure that we consistently handle signed and unsigned extensions correctly when decoding immediates from instruction opcodes. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target/ppc/internal.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 8b35863549..5d460247e2 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -52,20 +52,20 @@ FUNC_MASK(mask_u64, uint64_t, 64, UINT64_MAX); #define EXTRACT_HELPER(name, shift, nb) \ static inline uint32_t name(uint32_t opcode) \ { \ - return (opcode >> (shift)) & ((1 << (nb)) - 1); \ + return extract32(opcode, shift, nb); \ } #define EXTRACT_SHELPER(name, shift, nb) \ static inline int32_t name(uint32_t opcode) \ { \ - return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \ + return sextract32(opcode, shift, nb); \ } #define EXTRACT_HELPER_SPLIT(name, shift1, nb1, shift2, nb2) \ static inline uint32_t name(uint32_t opcode) \ { \ - return (((opcode >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \ - ((opcode >> (shift2)) & ((1 << (nb2)) - 1)); \ + return extract32(opcode, shift1, nb1) << nb2 | \ + extract32(opcode, shift2, nb2); \ } #define EXTRACT_HELPER_SPLIT_3(name, \ From 1a404c91bd62a2e27a7629901ce3c802397f3237 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 2 Jan 2019 09:14:17 +0000 Subject: [PATCH 07/29] target/ppc: introduce get_fpr() and set_fpr() helpers for FP register access These helpers allow us to move FP register values to/from the specified TCGv_i64 argument in the VSR helpers to be introduced shortly. To prevent FP helpers accessing the cpu_fpr array directly, add extra TCG temporaries as required. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Acked-by: David Gibson Signed-off-by: David Gibson --- target/ppc/translate.c | 10 + target/ppc/translate/fp-impl.inc.c | 486 ++++++++++++++++++++++------- 2 files changed, 386 insertions(+), 110 deletions(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 96894ab9a8..9cecab42f3 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6699,6 +6699,16 @@ static inline void gen_##name(DisasContext *ctx) \ GEN_TM_PRIV_NOOP(treclaim); GEN_TM_PRIV_NOOP(trechkpt); +static inline void get_fpr(TCGv_i64 dst, int regno) +{ + tcg_gen_mov_i64(dst, cpu_fpr[regno]); +} + +static inline void set_fpr(int regno, TCGv_i64 src) +{ + tcg_gen_mov_i64(cpu_fpr[regno], src); +} + #include "translate/fp-impl.inc.c" #include "translate/vmx-impl.inc.c" diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c index 08770ba9f5..0f21a4e477 100644 --- a/target/ppc/translate/fp-impl.inc.c +++ b/target/ppc/translate/fp-impl.inc.c @@ -34,24 +34,37 @@ static void gen_set_cr1_from_fpscr(DisasContext *ctx) #define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \ static void gen_f##name(DisasContext *ctx) \ { \ + TCGv_i64 t0; \ + TCGv_i64 t1; \ + TCGv_i64 t2; \ + TCGv_i64 t3; \ if (unlikely(!ctx->fpu_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ } \ + t0 = tcg_temp_new_i64(); \ + t1 = tcg_temp_new_i64(); \ + t2 = tcg_temp_new_i64(); \ + t3 = tcg_temp_new_i64(); \ 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)]); \ + get_fpr(t0, rA(ctx->opcode)); \ + get_fpr(t1, rC(ctx->opcode)); \ + get_fpr(t2, rB(ctx->opcode)); \ + gen_helper_f##op(t3, cpu_env, t0, t1, t2); \ if (isfloat) { \ - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rD(ctx->opcode)]); \ + gen_helper_frsp(t3, cpu_env, t3); \ } \ + set_fpr(rD(ctx->opcode), t3); \ if (set_fprf) { \ - gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \ + gen_compute_fprf_float64(t3); \ } \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i64(t1); \ + tcg_temp_free_i64(t2); \ + tcg_temp_free_i64(t3); \ } #define GEN_FLOAT_ACB(name, op2, set_fprf, type) \ @@ -61,24 +74,33 @@ _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) \ { \ + TCGv_i64 t0; \ + TCGv_i64 t1; \ + TCGv_i64 t2; \ if (unlikely(!ctx->fpu_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ } \ + t0 = tcg_temp_new_i64(); \ + t1 = tcg_temp_new_i64(); \ + t2 = tcg_temp_new_i64(); \ gen_reset_fpstatus(); \ - gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rA(ctx->opcode)], \ - cpu_fpr[rB(ctx->opcode)]); \ + get_fpr(t0, rA(ctx->opcode)); \ + get_fpr(t1, rB(ctx->opcode)); \ + gen_helper_f##op(t2, cpu_env, t0, t1); \ if (isfloat) { \ - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rD(ctx->opcode)]); \ + gen_helper_frsp(t2, cpu_env, t2); \ } \ + set_fpr(rD(ctx->opcode), t2); \ if (set_fprf) { \ - gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \ + gen_compute_fprf_float64(t2); \ } \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i64(t1); \ + tcg_temp_free_i64(t2); \ } #define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \ _GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ @@ -87,24 +109,33 @@ _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) \ { \ + TCGv_i64 t0; \ + TCGv_i64 t1; \ + TCGv_i64 t2; \ if (unlikely(!ctx->fpu_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ } \ + t0 = tcg_temp_new_i64(); \ + t1 = tcg_temp_new_i64(); \ + t2 = tcg_temp_new_i64(); \ gen_reset_fpstatus(); \ - gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rA(ctx->opcode)], \ - cpu_fpr[rC(ctx->opcode)]); \ + get_fpr(t0, rA(ctx->opcode)); \ + get_fpr(t1, rC(ctx->opcode)); \ + gen_helper_f##op(t2, cpu_env, t0, t1); \ if (isfloat) { \ - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rD(ctx->opcode)]); \ + gen_helper_frsp(t2, cpu_env, t2); \ } \ + set_fpr(rD(ctx->opcode), t2); \ if (set_fprf) { \ - gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \ + gen_compute_fprf_float64(t2); \ } \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i64(t1); \ + tcg_temp_free_i64(t2); \ } #define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \ _GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ @@ -113,37 +144,51 @@ _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) \ { \ + TCGv_i64 t0; \ + TCGv_i64 t1; \ if (unlikely(!ctx->fpu_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ } \ + t0 = tcg_temp_new_i64(); \ + t1 = tcg_temp_new_i64(); \ gen_reset_fpstatus(); \ - gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rB(ctx->opcode)]); \ + get_fpr(t0, rB(ctx->opcode)); \ + gen_helper_f##name(t1, cpu_env, t0); \ + set_fpr(rD(ctx->opcode), t1); \ if (set_fprf) { \ - gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \ + gen_compute_fprf_float64(t1); \ } \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i64(t1); \ } #define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \ static void gen_f##name(DisasContext *ctx) \ { \ + TCGv_i64 t0; \ + TCGv_i64 t1; \ if (unlikely(!ctx->fpu_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ } \ + t0 = tcg_temp_new_i64(); \ + t1 = tcg_temp_new_i64(); \ gen_reset_fpstatus(); \ - gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ - cpu_fpr[rB(ctx->opcode)]); \ + get_fpr(t0, rB(ctx->opcode)); \ + gen_helper_f##name(t1, cpu_env, t0); \ + set_fpr(rD(ctx->opcode), t1); \ if (set_fprf) { \ - gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \ + gen_compute_fprf_float64(t1); \ } \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i64(t1); \ } /* fadd - fadds */ @@ -165,19 +210,25 @@ GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE); /* frsqrtes */ static void gen_frsqrtes(DisasContext *ctx) { + TCGv_i64 t0; + TCGv_i64 t1; if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; } + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); 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_float64(cpu_fpr[rD(ctx->opcode)]); + get_fpr(t0, rB(ctx->opcode)); + gen_helper_frsqrte(t1, cpu_env, t0); + gen_helper_frsp(t1, cpu_env, t1); + set_fpr(rD(ctx->opcode), t1); + gen_compute_fprf_float64(t1); if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_cr1_from_fpscr(ctx); } + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } /* fsel */ @@ -189,34 +240,47 @@ GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT); /* fsqrt */ static void gen_fsqrt(DisasContext *ctx) { + TCGv_i64 t0; + TCGv_i64 t1; if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; } + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); gen_reset_fpstatus(); - gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env, - cpu_fpr[rB(ctx->opcode)]); - gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); + get_fpr(t0, rB(ctx->opcode)); + gen_helper_fsqrt(t1, cpu_env, t0); + set_fpr(rD(ctx->opcode), t1); + gen_compute_fprf_float64(t1); if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_cr1_from_fpscr(ctx); } + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } static void gen_fsqrts(DisasContext *ctx) { + TCGv_i64 t0; + TCGv_i64 t1; if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; } + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); 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_float64(cpu_fpr[rD(ctx->opcode)]); + get_fpr(t0, rB(ctx->opcode)); + gen_helper_fsqrt(t1, cpu_env, t0); + gen_helper_frsp(t1, cpu_env, t1); + set_fpr(rD(ctx->opcode), t1); + gen_compute_fprf_float64(t1); if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_cr1_from_fpscr(ctx); } + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } /*** Floating-Point multiply-and-add ***/ @@ -268,21 +332,32 @@ GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT); static void gen_ftdiv(DisasContext *ctx) { + TCGv_i64 t0; + TCGv_i64 t1; 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)]); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + get_fpr(t0, rA(ctx->opcode)); + get_fpr(t1, rB(ctx->opcode)); + gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], t0, t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } static void gen_ftsqrt(DisasContext *ctx) { + TCGv_i64 t0; 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)]); + t0 = tcg_temp_new_i64(); + get_fpr(t0, rB(ctx->opcode)); + gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], t0); + tcg_temp_free_i64(t0); } @@ -293,32 +368,46 @@ static void gen_ftsqrt(DisasContext *ctx) static void gen_fcmpo(DisasContext *ctx) { TCGv_i32 crf; + TCGv_i64 t0; + TCGv_i64 t1; if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; } + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); 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); + get_fpr(t0, rA(ctx->opcode)); + get_fpr(t1, rB(ctx->opcode)); + gen_helper_fcmpo(cpu_env, t0, t1, crf); tcg_temp_free_i32(crf); gen_helper_float_check_status(cpu_env); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } /* fcmpu */ static void gen_fcmpu(DisasContext *ctx) { TCGv_i32 crf; + TCGv_i64 t0; + TCGv_i64 t1; if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; } + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); 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); + get_fpr(t0, rA(ctx->opcode)); + get_fpr(t1, rB(ctx->opcode)); + gen_helper_fcmpu(cpu_env, t0, t1, crf); tcg_temp_free_i32(crf); gen_helper_float_check_status(cpu_env); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } /*** Floating-point move ***/ @@ -326,100 +415,153 @@ static void gen_fcmpu(DisasContext *ctx) /* XXX: beware that fabs never checks for NaNs nor update FPSCR */ static void gen_fabs(DisasContext *ctx) { + TCGv_i64 t0; + TCGv_i64 t1; 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)); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + get_fpr(t0, rB(ctx->opcode)); + tcg_gen_andi_i64(t1, t0, ~(1ULL << 63)); + set_fpr(rD(ctx->opcode), t1); if (unlikely(Rc(ctx->opcode))) { gen_set_cr1_from_fpscr(ctx); } + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } /* fmr - fmr. */ /* XXX: beware that fmr never checks for NaNs nor update FPSCR */ static void gen_fmr(DisasContext *ctx) { + TCGv_i64 t0; 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)]); + t0 = tcg_temp_new_i64(); + get_fpr(t0, rB(ctx->opcode)); + set_fpr(rD(ctx->opcode), t0); if (unlikely(Rc(ctx->opcode))) { gen_set_cr1_from_fpscr(ctx); } + tcg_temp_free_i64(t0); } /* fnabs */ /* XXX: beware that fnabs never checks for NaNs nor update FPSCR */ static void gen_fnabs(DisasContext *ctx) { + TCGv_i64 t0; + TCGv_i64 t1; 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); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + get_fpr(t0, rB(ctx->opcode)); + tcg_gen_ori_i64(t1, t0, 1ULL << 63); + set_fpr(rD(ctx->opcode), t1); if (unlikely(Rc(ctx->opcode))) { gen_set_cr1_from_fpscr(ctx); } + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } /* fneg */ /* XXX: beware that fneg never checks for NaNs nor update FPSCR */ static void gen_fneg(DisasContext *ctx) { + TCGv_i64 t0; + TCGv_i64 t1; 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); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + get_fpr(t0, rB(ctx->opcode)); + tcg_gen_xori_i64(t1, t0, 1ULL << 63); + set_fpr(rD(ctx->opcode), t1); if (unlikely(Rc(ctx->opcode))) { gen_set_cr1_from_fpscr(ctx); } + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } /* fcpsgn: PowerPC 2.05 specification */ /* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */ static void gen_fcpsgn(DisasContext *ctx) { + TCGv_i64 t0; + TCGv_i64 t1; + TCGv_i64 t2; 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); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + get_fpr(t0, rA(ctx->opcode)); + get_fpr(t1, rB(ctx->opcode)); + tcg_gen_deposit_i64(t2, t0, t1, 0, 63); + set_fpr(rD(ctx->opcode), t2); if (unlikely(Rc(ctx->opcode))) { gen_set_cr1_from_fpscr(ctx); } + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); } static void gen_fmrgew(DisasContext *ctx) { TCGv_i64 b0; + TCGv_i64 t0; + TCGv_i64 t1; 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); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + get_fpr(t0, rB(ctx->opcode)); + tcg_gen_shri_i64(b0, t0, 32); + get_fpr(t0, rA(ctx->opcode)); + tcg_gen_deposit_i64(t1, t0, b0, 0, 32); + set_fpr(rD(ctx->opcode), t1); tcg_temp_free_i64(b0); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } static void gen_fmrgow(DisasContext *ctx) { + TCGv_i64 t0; + TCGv_i64 t1; + TCGv_i64 t2; 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); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + get_fpr(t0, rB(ctx->opcode)); + get_fpr(t1, rA(ctx->opcode)); + tcg_gen_deposit_i64(t2, t0, t1, 32, 32); + set_fpr(rD(ctx->opcode), t2); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); } /*** Floating-Point status & ctrl register ***/ @@ -458,15 +600,19 @@ static void gen_mcrfs(DisasContext *ctx) /* mffs */ static void gen_mffs(DisasContext *ctx) { + TCGv_i64 t0; if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; } + t0 = tcg_temp_new_i64(); gen_reset_fpstatus(); - tcg_gen_extu_tl_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr); + tcg_gen_extu_tl_i64(t0, cpu_fpscr); + set_fpr(rD(ctx->opcode), t0); if (unlikely(Rc(ctx->opcode))) { gen_set_cr1_from_fpscr(ctx); } + tcg_temp_free_i64(t0); } /* mtfsb0 */ @@ -522,6 +668,7 @@ static void gen_mtfsb1(DisasContext *ctx) static void gen_mtfsf(DisasContext *ctx) { TCGv_i32 t0; + TCGv_i64 t1; int flm, l, w; if (unlikely(!ctx->fpu_enabled)) { @@ -541,7 +688,9 @@ static void gen_mtfsf(DisasContext *ctx) } else { t0 = tcg_const_i32(flm << (w * 8)); } - gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0); + t1 = tcg_temp_new_i64(); + get_fpr(t1, rB(ctx->opcode)); + gen_helper_store_fpscr(cpu_env, t1, t0); tcg_temp_free_i32(t0); if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); @@ -549,6 +698,7 @@ static void gen_mtfsf(DisasContext *ctx) } /* We can raise a differed exception */ gen_helper_float_check_status(cpu_env); + tcg_temp_free_i64(t1); } /* mtfsfi */ @@ -588,21 +738,26 @@ static void gen_mtfsfi(DisasContext *ctx) static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 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_i64(); \ gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \ + gen_qemu_##ldop(ctx, t0, EA); \ + set_fpr(rD(ctx->opcode), t0); \ tcg_temp_free(EA); \ + tcg_temp_free_i64(t0); \ } #define GEN_LDUF(name, ldop, opc, type) \ static void glue(gen_, name##u)(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 t0; \ if (unlikely(!ctx->fpu_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ @@ -613,20 +768,25 @@ static void glue(gen_, name##u)(DisasContext *ctx) } \ gen_set_access_type(ctx, ACCESS_FLOAT); \ EA = tcg_temp_new(); \ + t0 = tcg_temp_new_i64(); \ gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \ + gen_qemu_##ldop(ctx, t0, EA); \ + set_fpr(rD(ctx->opcode), t0); \ tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ tcg_temp_free(EA); \ + tcg_temp_free_i64(t0); \ } #define GEN_LDUXF(name, ldop, opc, type) \ static void glue(gen_, name##ux)(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 t0; \ if (unlikely(!ctx->fpu_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ } \ + t0 = tcg_temp_new_i64(); \ if (unlikely(rA(ctx->opcode) == 0)) { \ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ return; \ @@ -634,24 +794,30 @@ static void glue(gen_, name##ux)(DisasContext *ctx) 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); \ + gen_qemu_##ldop(ctx, t0, EA); \ + set_fpr(rD(ctx->opcode), t0); \ tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ tcg_temp_free(EA); \ + tcg_temp_free_i64(t0); \ } #define GEN_LDXF(name, ldop, opc2, opc3, type) \ static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 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_i64(); \ gen_addr_reg_index(ctx, EA); \ - gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \ + gen_qemu_##ldop(ctx, t0, EA); \ + set_fpr(rD(ctx->opcode), t0); \ tcg_temp_free(EA); \ + tcg_temp_free_i64(t0); \ } #define GEN_LDFS(name, ldop, op, type) \ @@ -677,6 +843,7 @@ GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT); static void gen_lfdepx(DisasContext *ctx) { TCGv EA; + TCGv_i64 t0; CHK_SV; if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); @@ -684,16 +851,19 @@ static void gen_lfdepx(DisasContext *ctx) } gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); + t0 = tcg_temp_new_i64(); gen_addr_reg_index(ctx, EA); - tcg_gen_qemu_ld_i64(cpu_fpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_LOAD, - DEF_MEMOP(MO_Q)); + tcg_gen_qemu_ld_i64(t0, EA, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_Q)); + set_fpr(rD(ctx->opcode), t0); tcg_temp_free(EA); + tcg_temp_free_i64(t0); } /* lfdp */ static void gen_lfdp(DisasContext *ctx) { TCGv EA; + TCGv_i64 t0; if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; @@ -701,24 +871,31 @@ static void gen_lfdp(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0); + t0 = tcg_temp_new_i64(); /* We only need to swap high and low halves. gen_qemu_ld64_i64 does necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, t0, EA); + set_fpr(rD(ctx->opcode) + 1, t0); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, t0, EA); + set_fpr(rD(ctx->opcode), t0); } else { - gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, t0, EA); + set_fpr(rD(ctx->opcode), t0); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, t0, EA); + set_fpr(rD(ctx->opcode) + 1, t0); } tcg_temp_free(EA); + tcg_temp_free_i64(t0); } /* lfdpx */ static void gen_lfdpx(DisasContext *ctx) { TCGv EA; + TCGv_i64 t0; if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; @@ -726,18 +903,24 @@ static void gen_lfdpx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); + t0 = tcg_temp_new_i64(); /* We only need to swap high and low halves. gen_qemu_ld64_i64 does necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, t0, EA); + set_fpr(rD(ctx->opcode) + 1, t0); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, t0, EA); + set_fpr(rD(ctx->opcode), t0); } else { - gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, t0, EA); + set_fpr(rD(ctx->opcode), t0); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, t0, EA); + set_fpr(rD(ctx->opcode) + 1, t0); } tcg_temp_free(EA); + tcg_temp_free_i64(t0); } /* lfiwax */ @@ -745,6 +928,7 @@ static void gen_lfiwax(DisasContext *ctx) { TCGv EA; TCGv t0; + TCGv_i64 t1; if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; @@ -752,47 +936,59 @@ static void gen_lfiwax(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); t0 = tcg_temp_new(); + t1 = tcg_temp_new_i64(); gen_addr_reg_index(ctx, EA); gen_qemu_ld32s(ctx, t0, EA); - tcg_gen_ext_tl_i64(cpu_fpr[rD(ctx->opcode)], t0); + tcg_gen_ext_tl_i64(t1, t0); + set_fpr(rD(ctx->opcode), t1); tcg_temp_free(EA); tcg_temp_free(t0); + tcg_temp_free_i64(t1); } /* lfiwzx */ static void gen_lfiwzx(DisasContext *ctx) { TCGv EA; + TCGv_i64 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_i64(); gen_addr_reg_index(ctx, EA); - gen_qemu_ld32u_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld32u_i64(ctx, t0, EA); + set_fpr(rD(ctx->opcode), t0); tcg_temp_free(EA); + tcg_temp_free_i64(t0); } /*** Floating-point store ***/ #define GEN_STF(name, stop, opc, type) \ static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 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_i64(); \ gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ + get_fpr(t0, rS(ctx->opcode)); \ + gen_qemu_##stop(ctx, t0, EA); \ tcg_temp_free(EA); \ + tcg_temp_free_i64(t0); \ } #define GEN_STUF(name, stop, opc, type) \ static void glue(gen_, name##u)(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 t0; \ if (unlikely(!ctx->fpu_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ @@ -803,16 +999,20 @@ static void glue(gen_, name##u)(DisasContext *ctx) } \ gen_set_access_type(ctx, ACCESS_FLOAT); \ EA = tcg_temp_new(); \ + t0 = tcg_temp_new_i64(); \ gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ + get_fpr(t0, rS(ctx->opcode)); \ + gen_qemu_##stop(ctx, t0, EA); \ tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ tcg_temp_free(EA); \ + tcg_temp_free_i64(t0); \ } #define GEN_STUXF(name, stop, opc, type) \ static void glue(gen_, name##ux)(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 t0; \ if (unlikely(!ctx->fpu_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_FPU); \ return; \ @@ -823,25 +1023,32 @@ static void glue(gen_, name##ux)(DisasContext *ctx) } \ gen_set_access_type(ctx, ACCESS_FLOAT); \ EA = tcg_temp_new(); \ + t0 = tcg_temp_new_i64(); \ gen_addr_reg_index(ctx, EA); \ - gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ + get_fpr(t0, rS(ctx->opcode)); \ + gen_qemu_##stop(ctx, t0, EA); \ tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ tcg_temp_free(EA); \ + tcg_temp_free_i64(t0); \ } #define GEN_STXF(name, stop, opc2, opc3, type) \ static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 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_i64(); \ gen_addr_reg_index(ctx, EA); \ - gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \ + get_fpr(t0, rS(ctx->opcode)); \ + gen_qemu_##stop(ctx, t0, EA); \ tcg_temp_free(EA); \ + tcg_temp_free_i64(t0); \ } #define GEN_STFS(name, stop, op, type) \ @@ -867,6 +1074,7 @@ GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT); static void gen_stfdepx(DisasContext *ctx) { TCGv EA; + TCGv_i64 t0; CHK_SV; if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); @@ -874,60 +1082,76 @@ static void gen_stfdepx(DisasContext *ctx) } gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); + t0 = tcg_temp_new_i64(); gen_addr_reg_index(ctx, EA); - tcg_gen_qemu_st_i64(cpu_fpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_STORE, - DEF_MEMOP(MO_Q)); + get_fpr(t0, rD(ctx->opcode)); + tcg_gen_qemu_st_i64(t0, EA, PPC_TLB_EPID_STORE, DEF_MEMOP(MO_Q)); tcg_temp_free(EA); + tcg_temp_free_i64(t0); } /* stfdp */ static void gen_stfdp(DisasContext *ctx) { TCGv EA; + TCGv_i64 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_i64(); gen_addr_imm_index(ctx, EA, 0); /* We only need to swap high and low halves. gen_qemu_st64_i64 does necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + get_fpr(t0, rD(ctx->opcode) + 1); + gen_qemu_st64_i64(ctx, t0, EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + get_fpr(t0, rD(ctx->opcode)); + gen_qemu_st64_i64(ctx, t0, EA); } else { - gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + get_fpr(t0, rD(ctx->opcode)); + gen_qemu_st64_i64(ctx, t0, EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + get_fpr(t0, rD(ctx->opcode) + 1); + gen_qemu_st64_i64(ctx, t0, EA); } tcg_temp_free(EA); + tcg_temp_free_i64(t0); } /* stfdpx */ static void gen_stfdpx(DisasContext *ctx) { TCGv EA; + TCGv_i64 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_i64(); gen_addr_reg_index(ctx, EA); /* We only need to swap high and low halves. gen_qemu_st64_i64 does necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + get_fpr(t0, rD(ctx->opcode) + 1); + gen_qemu_st64_i64(ctx, t0, EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + get_fpr(t0, rD(ctx->opcode)); + gen_qemu_st64_i64(ctx, t0, EA); } else { - gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + get_fpr(t0, rD(ctx->opcode)); + gen_qemu_st64_i64(ctx, t0, EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + get_fpr(t0, rD(ctx->opcode) + 1); + gen_qemu_st64_i64(ctx, t0, EA); } tcg_temp_free(EA); + tcg_temp_free_i64(t0); } /* Optional: */ @@ -949,13 +1173,18 @@ static void gen_lfq(DisasContext *ctx) { int rd = rD(ctx->opcode); TCGv t0; + TCGv_i64 t1; gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); + t1 = tcg_temp_new_i64(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, t1, t0); + set_fpr(rd, t1); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); + gen_qemu_ld64_i64(ctx, t1, t0); + set_fpr((rd + 1) % 32, t1); tcg_temp_free(t0); + tcg_temp_free_i64(t1); } /* lfqu */ @@ -964,17 +1193,22 @@ static void gen_lfqu(DisasContext *ctx) int ra = rA(ctx->opcode); int rd = rD(ctx->opcode); TCGv t0, t1; + TCGv_i64 t2; gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); t1 = tcg_temp_new(); + t2 = tcg_temp_new_i64(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, t2, t0); + set_fpr(rd, t2); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); + gen_qemu_ld64_i64(ctx, t2, t1); + set_fpr((rd + 1) % 32, t2); if (ra != 0) tcg_gen_mov_tl(cpu_gpr[ra], t0); tcg_temp_free(t0); tcg_temp_free(t1); + tcg_temp_free_i64(t2); } /* lfqux */ @@ -984,16 +1218,21 @@ static void gen_lfqux(DisasContext *ctx) int rd = rD(ctx->opcode); gen_set_access_type(ctx, ACCESS_FLOAT); TCGv t0, t1; + TCGv_i64 t2; + t2 = tcg_temp_new_i64(); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, t2, t0); + set_fpr(rd, t2); t1 = tcg_temp_new(); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); + gen_qemu_ld64_i64(ctx, t2, t1); + set_fpr((rd + 1) % 32, t2); tcg_temp_free(t1); if (ra != 0) tcg_gen_mov_tl(cpu_gpr[ra], t0); tcg_temp_free(t0); + tcg_temp_free_i64(t2); } /* lfqx */ @@ -1001,13 +1240,18 @@ static void gen_lfqx(DisasContext *ctx) { int rd = rD(ctx->opcode); TCGv t0; + TCGv_i64 t1; gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); + t1 = tcg_temp_new_i64(); gen_addr_reg_index(ctx, t0); - gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, t1, t0); + set_fpr(rd, t1); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); + gen_qemu_ld64_i64(ctx, t1, t0); + set_fpr((rd + 1) % 32, t1); tcg_temp_free(t0); + tcg_temp_free_i64(t1); } /* stfq */ @@ -1015,13 +1259,18 @@ static void gen_stfq(DisasContext *ctx) { int rd = rD(ctx->opcode); TCGv t0; + TCGv_i64 t1; gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); + t1 = tcg_temp_new_i64(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); + get_fpr(t1, rd); + gen_qemu_st64_i64(ctx, t1, t0); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); + get_fpr(t1, (rd + 1) % 32); + gen_qemu_st64_i64(ctx, t1, t0); tcg_temp_free(t0); + tcg_temp_free_i64(t1); } /* stfqu */ @@ -1030,17 +1279,23 @@ static void gen_stfqu(DisasContext *ctx) int ra = rA(ctx->opcode); int rd = rD(ctx->opcode); TCGv t0, t1; + TCGv_i64 t2; gen_set_access_type(ctx, ACCESS_FLOAT); + t2 = tcg_temp_new_i64(); t0 = tcg_temp_new(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); + get_fpr(t2, rd); + gen_qemu_st64_i64(ctx, t2, t0); t1 = tcg_temp_new(); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); + get_fpr(t2, (rd + 1) % 32); + gen_qemu_st64_i64(ctx, t2, t1); tcg_temp_free(t1); - if (ra != 0) + if (ra != 0) { tcg_gen_mov_tl(cpu_gpr[ra], t0); + } tcg_temp_free(t0); + tcg_temp_free_i64(t2); } /* stfqux */ @@ -1049,17 +1304,23 @@ static void gen_stfqux(DisasContext *ctx) int ra = rA(ctx->opcode); int rd = rD(ctx->opcode); TCGv t0, t1; + TCGv_i64 t2; gen_set_access_type(ctx, ACCESS_FLOAT); + t2 = tcg_temp_new_i64(); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); + get_fpr(t2, rd); + gen_qemu_st64_i64(ctx, t2, t0); t1 = tcg_temp_new(); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); + get_fpr(t2, (rd + 1) % 32); + gen_qemu_st64_i64(ctx, t2, t1); tcg_temp_free(t1); - if (ra != 0) + if (ra != 0) { tcg_gen_mov_tl(cpu_gpr[ra], t0); + } tcg_temp_free(t0); + tcg_temp_free_i64(t2); } /* stfqx */ @@ -1067,13 +1328,18 @@ static void gen_stfqx(DisasContext *ctx) { int rd = rD(ctx->opcode); TCGv t0; + TCGv_i64 t1; gen_set_access_type(ctx, ACCESS_FLOAT); + t1 = tcg_temp_new_i64(); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); + get_fpr(t1, rd); + gen_qemu_st64_i64(ctx, t1, t0); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); + get_fpr(t1, (rd + 1) % 32); + gen_qemu_st64_i64(ctx, t1, t0); tcg_temp_free(t0); + tcg_temp_free_i64(t1); } #undef _GEN_FLOAT_ACB From c4a18dbf52261ec505214d55d8681deeb2e33524 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 2 Jan 2019 09:14:18 +0000 Subject: [PATCH 08/29] target/ppc: introduce get_avr64() and set_avr64() helpers for VMX register access These helpers allow us to move AVR register values to/from the specified TCGv_i64 argument. To prevent VMX helpers accessing the cpu_avr{l,h} arrays directly, add extra TCG temporaries as required. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Acked-by: David Gibson Signed-off-by: David Gibson --- target/ppc/translate.c | 10 ++ target/ppc/translate/vmx-impl.inc.c | 145 ++++++++++++++++++++++------ 2 files changed, 123 insertions(+), 32 deletions(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 9cecab42f3..3bb24e7310 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6709,6 +6709,16 @@ static inline void set_fpr(int regno, TCGv_i64 src) tcg_gen_mov_i64(cpu_fpr[regno], src); } +static inline void get_avr64(TCGv_i64 dst, int regno, bool high) +{ + tcg_gen_mov_i64(dst, (high ? cpu_avrh : cpu_avrl)[regno]); +} + +static inline void set_avr64(int regno, TCGv_i64 src, bool high) +{ + tcg_gen_mov_i64((high ? cpu_avrh : cpu_avrl)[regno], src); +} + #include "translate/fp-impl.inc.c" #include "translate/vmx-impl.inc.c" diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c index 3cb6fc2926..5e8327e9a3 100644 --- a/target/ppc/translate/vmx-impl.inc.c +++ b/target/ppc/translate/vmx-impl.inc.c @@ -18,52 +18,66 @@ static inline TCGv_ptr gen_avr_ptr(int reg) static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 avr; \ if (unlikely(!ctx->altivec_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VPU); \ return; \ } \ gen_set_access_type(ctx, ACCESS_INT); \ + avr = tcg_temp_new_i64(); \ 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_i64 does \ necessary 64-bit byteswap already. */ \ if (ctx->le_mode) { \ - gen_qemu_ld64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, avr, EA); \ + set_avr64(rD(ctx->opcode), avr, false); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_ld64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, avr, EA); \ + set_avr64(rD(ctx->opcode), avr, true); \ } else { \ - gen_qemu_ld64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, avr, EA); \ + set_avr64(rD(ctx->opcode), avr, true); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_ld64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, avr, EA); \ + set_avr64(rD(ctx->opcode), avr, false); \ } \ tcg_temp_free(EA); \ + tcg_temp_free_i64(avr); \ } #define GEN_VR_STX(name, opc2, opc3) \ static void gen_st##name(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 avr; \ if (unlikely(!ctx->altivec_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VPU); \ return; \ } \ gen_set_access_type(ctx, ACCESS_INT); \ + avr = tcg_temp_new_i64(); \ 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_i64 does \ necessary 64-bit byteswap already. */ \ if (ctx->le_mode) { \ - gen_qemu_st64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + get_avr64(avr, rD(ctx->opcode), false); \ + gen_qemu_st64_i64(ctx, avr, EA); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_st64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + get_avr64(avr, rD(ctx->opcode), true); \ + gen_qemu_st64_i64(ctx, avr, EA); \ } else { \ - gen_qemu_st64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + get_avr64(avr, rD(ctx->opcode), true); \ + gen_qemu_st64_i64(ctx, avr, EA); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_st64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + get_avr64(avr, rD(ctx->opcode), false); \ + gen_qemu_st64_i64(ctx, avr, EA); \ } \ tcg_temp_free(EA); \ + tcg_temp_free_i64(avr); \ } #define GEN_VR_LVE(name, opc2, opc3, size) \ @@ -159,15 +173,20 @@ static void gen_lvsr(DisasContext *ctx) static void gen_mfvscr(DisasContext *ctx) { TCGv_i32 t; + TCGv_i64 avr; if (unlikely(!ctx->altivec_enabled)) { gen_exception(ctx, POWERPC_EXCP_VPU); return; } - tcg_gen_movi_i64(cpu_avrh[rD(ctx->opcode)], 0); + avr = tcg_temp_new_i64(); + tcg_gen_movi_i64(avr, 0); + set_avr64(rD(ctx->opcode), avr, true); 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_gen_extu_i32_i64(avr, t); + set_avr64(rD(ctx->opcode), avr, false); tcg_temp_free_i32(t); + tcg_temp_free_i64(avr); } static void gen_mtvscr(DisasContext *ctx) @@ -185,9 +204,10 @@ static void gen_mtvscr(DisasContext *ctx) #define GEN_VX_VMUL10(name, add_cin, ret_carry) \ static void glue(gen_, name)(DisasContext *ctx) \ { \ - TCGv_i64 t0 = tcg_temp_new_i64(); \ - TCGv_i64 t1 = tcg_temp_new_i64(); \ - TCGv_i64 t2 = tcg_temp_new_i64(); \ + TCGv_i64 t0; \ + TCGv_i64 t1; \ + TCGv_i64 t2; \ + TCGv_i64 avr; \ TCGv_i64 ten, z; \ \ if (unlikely(!ctx->altivec_enabled)) { \ @@ -195,30 +215,43 @@ static void glue(gen_, name)(DisasContext *ctx) \ return; \ } \ \ + t0 = tcg_temp_new_i64(); \ + t1 = tcg_temp_new_i64(); \ + t2 = tcg_temp_new_i64(); \ + avr = tcg_temp_new_i64(); \ ten = tcg_const_i64(10); \ z = tcg_const_i64(0); \ \ if (add_cin) { \ - tcg_gen_mulu2_i64(t0, t1, cpu_avrl[rA(ctx->opcode)], ten); \ - tcg_gen_andi_i64(t2, cpu_avrl[rB(ctx->opcode)], 0xF); \ - tcg_gen_add2_i64(cpu_avrl[rD(ctx->opcode)], t2, t0, t1, t2, z); \ + get_avr64(avr, rA(ctx->opcode), false); \ + tcg_gen_mulu2_i64(t0, t1, avr, ten); \ + get_avr64(avr, rB(ctx->opcode), false); \ + tcg_gen_andi_i64(t2, avr, 0xF); \ + tcg_gen_add2_i64(avr, t2, t0, t1, t2, z); \ + set_avr64(rD(ctx->opcode), avr, false); \ } else { \ - tcg_gen_mulu2_i64(cpu_avrl[rD(ctx->opcode)], t2, \ - cpu_avrl[rA(ctx->opcode)], ten); \ + get_avr64(avr, rA(ctx->opcode), false); \ + tcg_gen_mulu2_i64(avr, t2, avr, ten); \ + set_avr64(rD(ctx->opcode), avr, false); \ } \ \ if (ret_carry) { \ - tcg_gen_mulu2_i64(t0, t1, cpu_avrh[rA(ctx->opcode)], ten); \ - tcg_gen_add2_i64(t0, cpu_avrl[rD(ctx->opcode)], t0, t1, t2, z); \ - tcg_gen_movi_i64(cpu_avrh[rD(ctx->opcode)], 0); \ + get_avr64(avr, rA(ctx->opcode), true); \ + tcg_gen_mulu2_i64(t0, t1, avr, ten); \ + tcg_gen_add2_i64(t0, avr, t0, t1, t2, z); \ + set_avr64(rD(ctx->opcode), avr, false); \ + set_avr64(rD(ctx->opcode), z, true); \ } else { \ - tcg_gen_mul_i64(t0, cpu_avrh[rA(ctx->opcode)], ten); \ - tcg_gen_add_i64(cpu_avrh[rD(ctx->opcode)], t0, t2); \ + get_avr64(avr, rA(ctx->opcode), true); \ + tcg_gen_mul_i64(t0, avr, ten); \ + tcg_gen_add_i64(avr, t0, t2); \ + set_avr64(rD(ctx->opcode), avr, true); \ } \ \ tcg_temp_free_i64(t0); \ tcg_temp_free_i64(t1); \ tcg_temp_free_i64(t2); \ + tcg_temp_free_i64(avr); \ tcg_temp_free_i64(ten); \ tcg_temp_free_i64(z); \ } \ @@ -232,12 +265,31 @@ GEN_VX_VMUL10(vmul10ecuq, 1, 1); #define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3) \ static void glue(gen_, name)(DisasContext *ctx) \ { \ + TCGv_i64 t0; \ + TCGv_i64 t1; \ + TCGv_i64 avr; \ + \ 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)]); \ + t0 = tcg_temp_new_i64(); \ + t1 = tcg_temp_new_i64(); \ + avr = tcg_temp_new_i64(); \ + \ + get_avr64(t0, rA(ctx->opcode), true); \ + get_avr64(t1, rB(ctx->opcode), true); \ + tcg_op(avr, t0, t1); \ + set_avr64(rD(ctx->opcode), avr, true); \ + \ + get_avr64(t0, rA(ctx->opcode), false); \ + get_avr64(t1, rB(ctx->opcode), false); \ + tcg_op(avr, t0, t1); \ + set_avr64(rD(ctx->opcode), avr, false); \ + \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i64(t1); \ + tcg_temp_free_i64(avr); \ } GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16); @@ -406,6 +458,7 @@ GEN_VXFORM(vmrglw, 6, 6); static void gen_vmrgew(DisasContext *ctx) { TCGv_i64 tmp; + TCGv_i64 avr; int VT, VA, VB; if (unlikely(!ctx->altivec_enabled)) { gen_exception(ctx, POWERPC_EXCP_VPU); @@ -415,15 +468,28 @@ static void gen_vmrgew(DisasContext *ctx) 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); + avr = tcg_temp_new_i64(); + + get_avr64(avr, VB, true); + tcg_gen_shri_i64(tmp, avr, 32); + get_avr64(avr, VA, true); + tcg_gen_deposit_i64(avr, avr, tmp, 0, 32); + set_avr64(VT, avr, true); + + get_avr64(avr, VB, false); + tcg_gen_shri_i64(tmp, avr, 32); + get_avr64(avr, VA, false); + tcg_gen_deposit_i64(avr, avr, tmp, 0, 32); + set_avr64(VT, avr, false); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(avr); } static void gen_vmrgow(DisasContext *ctx) { + TCGv_i64 t0, t1; + TCGv_i64 avr; int VT, VA, VB; if (unlikely(!ctx->altivec_enabled)) { gen_exception(ctx, POWERPC_EXCP_VPU); @@ -432,9 +498,23 @@ static void gen_vmrgow(DisasContext *ctx) VT = rD(ctx->opcode); VA = rA(ctx->opcode); VB = rB(ctx->opcode); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + avr = tcg_temp_new_i64(); - 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); + get_avr64(t0, VB, true); + get_avr64(t1, VA, true); + tcg_gen_deposit_i64(avr, t0, t1, 32, 32); + set_avr64(VT, avr, true); + + get_avr64(t0, VB, false); + get_avr64(t1, VA, false); + tcg_gen_deposit_i64(avr, t0, t1, 32, 32); + set_avr64(VT, avr, false); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(avr); } GEN_VXFORM(vmuloub, 4, 0); @@ -790,7 +870,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv_ptr rb, rd; \ uint8_t uimm = UIMM4(ctx->opcode); \ - TCGv_i32 t0 = tcg_temp_new_i32(); \ + TCGv_i32 t0; \ if (unlikely(!ctx->altivec_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VPU); \ return; \ @@ -798,6 +878,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ if (uimm > splat_max) { \ uimm = 0; \ } \ + t0 = tcg_temp_new_i32(); \ tcg_gen_movi_i32(t0, uimm); \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ From 8b3b2d75c7c0481544e277dad226223245e058eb Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 2 Jan 2019 09:14:19 +0000 Subject: [PATCH 09/29] target/ppc: introduce get_cpu_vsr{l,h}() and set_cpu_vsr{l,h}() helpers for VSR register access These helpers allow us to move VSR register values to/from the specified TCGv_i64 argument. To prevent VSX helpers accessing the cpu_vsr array directly, add extra TCG temporaries as required. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Acked-by: David Gibson Signed-off-by: David Gibson --- target/ppc/translate/vsx-impl.inc.c | 862 ++++++++++++++++++++-------- 1 file changed, 638 insertions(+), 224 deletions(-) diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c index 85ed135d44..f0665df1a5 100644 --- a/target/ppc/translate/vsx-impl.inc.c +++ b/target/ppc/translate/vsx-impl.inc.c @@ -1,20 +1,48 @@ /*** VSX extension ***/ -static inline TCGv_i64 cpu_vsrh(int n) +static inline void get_vsr(TCGv_i64 dst, int n) +{ + tcg_gen_mov_i64(dst, cpu_vsr[n]); +} + +static inline void set_vsr(int n, TCGv_i64 src) +{ + tcg_gen_mov_i64(cpu_vsr[n], src); +} + +static inline void get_cpu_vsrh(TCGv_i64 dst, int n) { if (n < 32) { - return cpu_fpr[n]; + get_fpr(dst, n); } else { - return cpu_avrh[n-32]; + get_avr64(dst, n - 32, true); } } -static inline TCGv_i64 cpu_vsrl(int n) +static inline void get_cpu_vsrl(TCGv_i64 dst, int n) { if (n < 32) { - return cpu_vsr[n]; + get_vsr(dst, n); } else { - return cpu_avrl[n-32]; + get_avr64(dst, n - 32, false); + } +} + +static inline void set_cpu_vsrh(int n, TCGv_i64 src) +{ + if (n < 32) { + set_fpr(n, src); + } else { + set_avr64(n - 32, src, true); + } +} + +static inline void set_cpu_vsrl(int n, TCGv_i64 src) +{ + if (n < 32) { + set_vsr(n, src); + } else { + set_avr64(n - 32, src, false); } } @@ -22,16 +50,20 @@ static inline TCGv_i64 cpu_vsrl(int n) static void gen_##name(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 t0; \ if (unlikely(!ctx->vsx_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ + t0 = tcg_temp_new_i64(); \ 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); \ + gen_qemu_##operation(ctx, t0, EA); \ + set_cpu_vsrh(xT(ctx->opcode), t0); \ /* NOTE: cpu_vsrl is undefined */ \ tcg_temp_free(EA); \ + tcg_temp_free_i64(t0); \ } VSX_LOAD_SCALAR(lxsdx, ld64_i64) @@ -44,43 +76,60 @@ VSX_LOAD_SCALAR(lxsspx, ld32fs) static void gen_lxvd2x(DisasContext *ctx) { TCGv EA; + TCGv_i64 t0; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + t0 = tcg_temp_new_i64(); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - gen_qemu_ld64_i64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); + gen_qemu_ld64_i64(ctx, t0, EA); + set_cpu_vsrh(xT(ctx->opcode), t0); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64_i64(ctx, cpu_vsrl(xT(ctx->opcode)), EA); + gen_qemu_ld64_i64(ctx, t0, EA); + set_cpu_vsrl(xT(ctx->opcode), t0); tcg_temp_free(EA); + tcg_temp_free_i64(t0); } static void gen_lxvdsx(DisasContext *ctx) { TCGv EA; + TCGv_i64 t0; + TCGv_i64 t1; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - gen_qemu_ld64_i64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode))); + gen_qemu_ld64_i64(ctx, t0, EA); + set_cpu_vsrh(xT(ctx->opcode), t0); + tcg_gen_mov_i64(t1, t0); + set_cpu_vsrl(xT(ctx->opcode), t1); tcg_temp_free(EA); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } static void gen_lxvw4x(DisasContext *ctx) { TCGv EA; - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); + TCGv_i64 xth; + TCGv_i64 xtl; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + get_cpu_vsrh(xth, xT(ctx->opcode)); + get_cpu_vsrl(xtl, xT(ctx->opcode)); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); @@ -104,6 +153,8 @@ static void gen_lxvw4x(DisasContext *ctx) tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); } tcg_temp_free(EA); + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); } static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl, @@ -151,13 +202,17 @@ static void gen_bswap32x4(TCGv_i64 outh, TCGv_i64 outl, static void gen_lxvh8x(DisasContext *ctx) { TCGv EA; - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); + TCGv_i64 xth; + TCGv_i64 xtl; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + get_cpu_vsrh(xth, xT(ctx->opcode)); + get_cpu_vsrl(xtl, xT(ctx->opcode)); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); @@ -169,18 +224,24 @@ static void gen_lxvh8x(DisasContext *ctx) gen_bswap16x8(xth, xtl, xth, xtl); } tcg_temp_free(EA); + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); } static void gen_lxvb16x(DisasContext *ctx) { TCGv EA; - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); + TCGv_i64 xth; + TCGv_i64 xtl; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + get_cpu_vsrh(xth, xT(ctx->opcode)); + get_cpu_vsrl(xtl, xT(ctx->opcode)); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); @@ -188,6 +249,8 @@ static void gen_lxvb16x(DisasContext *ctx) tcg_gen_addi_tl(EA, EA, 8); tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); tcg_temp_free(EA); + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); } #define VSX_VECTOR_LOAD_STORE(name, op, indexed) \ @@ -195,15 +258,14 @@ static void gen_##name(DisasContext *ctx) \ { \ int xt; \ TCGv EA; \ - TCGv_i64 xth, xtl; \ + TCGv_i64 xth; \ + TCGv_i64 xtl; \ \ if (indexed) { \ xt = xT(ctx->opcode); \ } else { \ xt = DQxT(ctx->opcode); \ } \ - xth = cpu_vsrh(xt); \ - xtl = cpu_vsrl(xt); \ \ if (xt < 32) { \ if (unlikely(!ctx->vsx_enabled)) { \ @@ -216,6 +278,10 @@ static void gen_##name(DisasContext *ctx) \ return; \ } \ } \ + xth = tcg_temp_new_i64(); \ + xtl = tcg_temp_new_i64(); \ + get_cpu_vsrh(xth, xt); \ + get_cpu_vsrl(xtl, xt); \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ if (indexed) { \ @@ -225,14 +291,20 @@ static void gen_##name(DisasContext *ctx) \ } \ if (ctx->le_mode) { \ tcg_gen_qemu_##op(xtl, EA, ctx->mem_idx, MO_LEQ); \ + set_cpu_vsrl(xt, xtl); \ tcg_gen_addi_tl(EA, EA, 8); \ tcg_gen_qemu_##op(xth, EA, ctx->mem_idx, MO_LEQ); \ + set_cpu_vsrh(xt, xth); \ } else { \ tcg_gen_qemu_##op(xth, EA, ctx->mem_idx, MO_BEQ); \ + set_cpu_vsrh(xt, xth); \ tcg_gen_addi_tl(EA, EA, 8); \ tcg_gen_qemu_##op(xtl, EA, ctx->mem_idx, MO_BEQ); \ + set_cpu_vsrl(xt, xtl); \ } \ tcg_temp_free(EA); \ + tcg_temp_free_i64(xth); \ + tcg_temp_free_i64(xtl); \ } VSX_VECTOR_LOAD_STORE(lxv, ld_i64, 0) @@ -276,18 +348,22 @@ VSX_VECTOR_LOAD_STORE_LENGTH(stxvll) static void gen_##name(DisasContext *ctx) \ { \ TCGv EA; \ - TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32); \ + TCGv_i64 xth; \ \ if (unlikely(!ctx->altivec_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VPU); \ return; \ } \ + xth = tcg_temp_new_i64(); \ + get_cpu_vsrh(xth, rD(ctx->opcode) + 32); \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_imm_index(ctx, EA, 0x03); \ gen_qemu_##operation(ctx, xth, EA); \ + set_cpu_vsrh(rD(ctx->opcode) + 32, xth); \ /* NOTE: cpu_vsrl is undefined */ \ tcg_temp_free(EA); \ + tcg_temp_free_i64(xth); \ } VSX_LOAD_SCALAR_DS(lxsd, ld64_i64) @@ -297,15 +373,19 @@ VSX_LOAD_SCALAR_DS(lxssp, ld32fs) static void gen_##name(DisasContext *ctx) \ { \ TCGv EA; \ + TCGv_i64 t0; \ if (unlikely(!ctx->vsx_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ + t0 = tcg_temp_new_i64(); \ 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); \ + gen_qemu_##operation(ctx, t0, EA); \ + set_cpu_vsrh(xS(ctx->opcode), t0); \ tcg_temp_free(EA); \ + tcg_temp_free_i64(t0); \ } VSX_STORE_SCALAR(stxsdx, st64_i64) @@ -318,28 +398,38 @@ VSX_STORE_SCALAR(stxsspx, st32fs) static void gen_stxvd2x(DisasContext *ctx) { TCGv EA; + TCGv_i64 t0; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + t0 = tcg_temp_new_i64(); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - gen_qemu_st64_i64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); + get_cpu_vsrh(t0, xS(ctx->opcode)); + gen_qemu_st64_i64(ctx, t0, EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64_i64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); + get_cpu_vsrl(t0, xS(ctx->opcode)); + gen_qemu_st64_i64(ctx, t0, EA); tcg_temp_free(EA); + tcg_temp_free_i64(t0); } static void gen_stxvw4x(DisasContext *ctx) { - TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); - TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); TCGv EA; + TCGv_i64 xsh; + TCGv_i64 xsl; + if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xsh = tcg_temp_new_i64(); + xsl = tcg_temp_new_i64(); + get_cpu_vsrh(xsh, xS(ctx->opcode)); + get_cpu_vsrl(xsl, xS(ctx->opcode)); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); @@ -362,18 +452,24 @@ static void gen_stxvw4x(DisasContext *ctx) tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); } tcg_temp_free(EA); + tcg_temp_free_i64(xsh); + tcg_temp_free_i64(xsl); } static void gen_stxvh8x(DisasContext *ctx) { - TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); - TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); TCGv EA; + TCGv_i64 xsh; + TCGv_i64 xsl; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xsh = tcg_temp_new_i64(); + xsl = tcg_temp_new_i64(); + get_cpu_vsrh(xsh, xS(ctx->opcode)); + get_cpu_vsrl(xsl, xS(ctx->opcode)); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); @@ -393,18 +489,24 @@ static void gen_stxvh8x(DisasContext *ctx) tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); } tcg_temp_free(EA); + tcg_temp_free_i64(xsh); + tcg_temp_free_i64(xsl); } static void gen_stxvb16x(DisasContext *ctx) { - TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); - TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); TCGv EA; + TCGv_i64 xsh; + TCGv_i64 xsl; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xsh = tcg_temp_new_i64(); + xsl = tcg_temp_new_i64(); + get_cpu_vsrh(xsh, xS(ctx->opcode)); + get_cpu_vsrl(xsl, xS(ctx->opcode)); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); @@ -412,80 +514,144 @@ static void gen_stxvb16x(DisasContext *ctx) tcg_gen_addi_tl(EA, EA, 8); tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); tcg_temp_free(EA); + tcg_temp_free_i64(xsh); + tcg_temp_free_i64(xsl); } #define VSX_STORE_SCALAR_DS(name, operation) \ static void gen_##name(DisasContext *ctx) \ { \ TCGv EA; \ - TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32); \ + TCGv_i64 xth; \ \ if (unlikely(!ctx->altivec_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VPU); \ return; \ } \ + xth = tcg_temp_new_i64(); \ + get_cpu_vsrh(xth, rD(ctx->opcode) + 32); \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_imm_index(ctx, EA, 0x03); \ gen_qemu_##operation(ctx, xth, EA); \ /* NOTE: cpu_vsrl is undefined */ \ tcg_temp_free(EA); \ + tcg_temp_free_i64(xth); \ } VSX_LOAD_SCALAR_DS(stxsd, st64_i64) VSX_LOAD_SCALAR_DS(stxssp, st32fs) -#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); \ +static void gen_mfvsrwz(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(); + TCGv_i64 xsh = tcg_temp_new_i64(); + get_cpu_vsrh(xsh, xS(ctx->opcode)); + tcg_gen_ext32u_i64(tmp, xsh); + tcg_gen_trunc_i64_tl(cpu_gpr[rA(ctx->opcode)], tmp); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(xsh); } +static void gen_mtvsrwa(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(); + TCGv_i64 xsh = tcg_temp_new_i64(); + tcg_gen_extu_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ext32s_i64(xsh, tmp); + set_cpu_vsrh(xT(ctx->opcode), xsh); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(xsh); +} -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)]) +static void gen_mtvsrwz(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(); + TCGv_i64 xsh = tcg_temp_new_i64(); + tcg_gen_extu_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ext32u_i64(xsh, tmp); + set_cpu_vsrh(xT(ctx->opcode), xsh); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(xsh); +} #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); \ +static void gen_mfvsrd(DisasContext *ctx) +{ + TCGv_i64 t0; + 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; + } + } + t0 = tcg_temp_new_i64(); + get_cpu_vsrh(t0, xS(ctx->opcode)); + tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], t0); + tcg_temp_free_i64(t0); } -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)]) +static void gen_mtvsrd(DisasContext *ctx) +{ + TCGv_i64 t0; + 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; + } + } + t0 = tcg_temp_new_i64(); + tcg_gen_mov_i64(t0, cpu_gpr[rA(ctx->opcode)]); + set_cpu_vsrh(xT(ctx->opcode), t0); + tcg_temp_free_i64(t0); +} static void gen_mfvsrld(DisasContext *ctx) { + TCGv_i64 t0; if (xS(ctx->opcode) < 32) { if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); @@ -497,12 +663,15 @@ static void gen_mfvsrld(DisasContext *ctx) return; } } - - tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], cpu_vsrl(xS(ctx->opcode))); + t0 = tcg_temp_new_i64(); + get_cpu_vsrl(t0, xS(ctx->opcode)); + tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], t0); + tcg_temp_free_i64(t0); } static void gen_mtvsrdd(DisasContext *ctx) { + TCGv_i64 t0; if (xT(ctx->opcode) < 32) { if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); @@ -515,17 +684,22 @@ static void gen_mtvsrdd(DisasContext *ctx) } } + t0 = tcg_temp_new_i64(); if (!rA(ctx->opcode)) { - tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), 0); + tcg_gen_movi_i64(t0, 0); } else { - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_i64(t0, cpu_gpr[rA(ctx->opcode)]); } + set_cpu_vsrh(xT(ctx->opcode), t0); - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mov_i64(t0, cpu_gpr[rB(ctx->opcode)]); + set_cpu_vsrl(xT(ctx->opcode), t0); + tcg_temp_free_i64(t0); } static void gen_mtvsrws(DisasContext *ctx) { + TCGv_i64 t0; if (xT(ctx->opcode) < 32) { if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); @@ -538,55 +712,61 @@ static void gen_mtvsrws(DisasContext *ctx) } } - tcg_gen_deposit_i64(cpu_vsrl(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)], + t0 = tcg_temp_new_i64(); + tcg_gen_deposit_i64(t0, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 32, 32); - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xT(ctx->opcode))); + set_cpu_vsrl(xT(ctx->opcode), t0); + set_cpu_vsrh(xT(ctx->opcode), t0); + tcg_temp_free_i64(t0); } #endif static void gen_xxpermdi(DisasContext *ctx) { + TCGv_i64 xh, xl; + if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xh = tcg_temp_new_i64(); + xl = tcg_temp_new_i64(); + 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))); + get_cpu_vsrh(xh, xA(ctx->opcode)); } else { - tcg_gen_mov_i64(xh, cpu_vsrl(xA(ctx->opcode))); + get_cpu_vsrl(xh, xA(ctx->opcode)); } if ((DM(ctx->opcode) & 1) == 0) { - tcg_gen_mov_i64(xl, cpu_vsrh(xB(ctx->opcode))); + get_cpu_vsrh(xl, xB(ctx->opcode)); } else { - tcg_gen_mov_i64(xl, cpu_vsrl(xB(ctx->opcode))); + get_cpu_vsrl(xl, 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); + set_cpu_vsrh(xT(ctx->opcode), xh); + set_cpu_vsrl(xT(ctx->opcode), xl); } else { if ((DM(ctx->opcode) & 2) == 0) { - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode))); + get_cpu_vsrh(xh, xA(ctx->opcode)); + set_cpu_vsrh(xT(ctx->opcode), xh); } else { - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode))); + get_cpu_vsrl(xh, xA(ctx->opcode)); + set_cpu_vsrh(xT(ctx->opcode), xh); } if ((DM(ctx->opcode) & 1) == 0) { - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xB(ctx->opcode))); + get_cpu_vsrh(xl, xB(ctx->opcode)); + set_cpu_vsrl(xT(ctx->opcode), xl); } else { - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xB(ctx->opcode))); + get_cpu_vsrl(xl, xB(ctx->opcode)); + set_cpu_vsrl(xT(ctx->opcode), xl); } } + tcg_temp_free_i64(xh); + tcg_temp_free_i64(xl); } #define OP_ABS 1 @@ -606,7 +786,7 @@ static void glue(gen_, name)(DisasContext * ctx) \ } \ xb = tcg_temp_new_i64(); \ sgm = tcg_temp_new_i64(); \ - tcg_gen_mov_i64(xb, cpu_vsrh(xB(ctx->opcode))); \ + get_cpu_vsrh(xb, xB(ctx->opcode)); \ tcg_gen_movi_i64(sgm, sgn_mask); \ switch (op) { \ case OP_ABS: { \ @@ -623,7 +803,7 @@ static void glue(gen_, name)(DisasContext * ctx) \ } \ case OP_CPSGN: { \ TCGv_i64 xa = tcg_temp_new_i64(); \ - tcg_gen_mov_i64(xa, cpu_vsrh(xA(ctx->opcode))); \ + get_cpu_vsrh(xa, xA(ctx->opcode)); \ tcg_gen_and_i64(xa, xa, sgm); \ tcg_gen_andc_i64(xb, xb, sgm); \ tcg_gen_or_i64(xb, xb, xa); \ @@ -631,7 +811,7 @@ static void glue(gen_, name)(DisasContext * ctx) \ break; \ } \ } \ - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xb); \ + set_cpu_vsrh(xT(ctx->opcode), xb); \ tcg_temp_free_i64(xb); \ tcg_temp_free_i64(sgm); \ } @@ -647,7 +827,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ int xa; \ int xt = rD(ctx->opcode) + 32; \ int xb = rB(ctx->opcode) + 32; \ - TCGv_i64 xah, xbh, xbl, sgm; \ + TCGv_i64 xah, xbh, xbl, sgm, tmp; \ \ if (unlikely(!ctx->vsx_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ @@ -656,8 +836,9 @@ static void glue(gen_, name)(DisasContext *ctx) \ xbh = tcg_temp_new_i64(); \ xbl = tcg_temp_new_i64(); \ sgm = tcg_temp_new_i64(); \ - tcg_gen_mov_i64(xbh, cpu_vsrh(xb)); \ - tcg_gen_mov_i64(xbl, cpu_vsrl(xb)); \ + tmp = tcg_temp_new_i64(); \ + get_cpu_vsrh(xbh, xb); \ + get_cpu_vsrl(xbl, xb); \ tcg_gen_movi_i64(sgm, sgn_mask); \ switch (op) { \ case OP_ABS: \ @@ -672,17 +853,19 @@ static void glue(gen_, name)(DisasContext *ctx) \ case OP_CPSGN: \ xah = tcg_temp_new_i64(); \ xa = rA(ctx->opcode) + 32; \ - tcg_gen_and_i64(xah, cpu_vsrh(xa), sgm); \ + get_cpu_vsrh(tmp, xa); \ + tcg_gen_and_i64(xah, tmp, sgm); \ tcg_gen_andc_i64(xbh, xbh, sgm); \ tcg_gen_or_i64(xbh, xbh, xah); \ tcg_temp_free_i64(xah); \ break; \ } \ - tcg_gen_mov_i64(cpu_vsrh(xt), xbh); \ - tcg_gen_mov_i64(cpu_vsrl(xt), xbl); \ + set_cpu_vsrh(xt, xbh); \ + set_cpu_vsrl(xt, xbl); \ tcg_temp_free_i64(xbl); \ tcg_temp_free_i64(xbh); \ tcg_temp_free_i64(sgm); \ + tcg_temp_free_i64(tmp); \ } VSX_SCALAR_MOVE_QP(xsabsqp, OP_ABS, SGN_MASK_DP) @@ -701,8 +884,8 @@ static void glue(gen_, name)(DisasContext * ctx) \ 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))); \ + set_cpu_vsrh(xB(ctx->opcode), xbh); \ + set_cpu_vsrl(xB(ctx->opcode), xbl); \ tcg_gen_movi_i64(sgm, sgn_mask); \ switch (op) { \ case OP_ABS: { \ @@ -723,8 +906,8 @@ static void glue(gen_, name)(DisasContext * ctx) \ 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))); \ + get_cpu_vsrh(xah, xA(ctx->opcode)); \ + get_cpu_vsrl(xal, xA(ctx->opcode)); \ tcg_gen_and_i64(xah, xah, sgm); \ tcg_gen_and_i64(xal, xal, sgm); \ tcg_gen_andc_i64(xbh, xbh, sgm); \ @@ -736,8 +919,8 @@ static void glue(gen_, name)(DisasContext * ctx) \ break; \ } \ } \ - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xbh); \ - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xbl); \ + set_cpu_vsrh(xT(ctx->opcode), xbh); \ + set_cpu_vsrl(xT(ctx->opcode), xbl); \ tcg_temp_free_i64(xbh); \ tcg_temp_free_i64(xbl); \ tcg_temp_free_i64(sgm); \ @@ -768,12 +951,19 @@ static void gen_##name(DisasContext * ctx) \ #define GEN_VSX_HELPER_XT_XB_ENV(name, op1, op2, inval, type) \ static void gen_##name(DisasContext * ctx) \ { \ + TCGv_i64 t0; \ + TCGv_i64 t1; \ if (unlikely(!ctx->vsx_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ - gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env, \ - cpu_vsrh(xB(ctx->opcode))); \ + t0 = tcg_temp_new_i64(); \ + t1 = tcg_temp_new_i64(); \ + get_cpu_vsrh(t0, xB(ctx->opcode)); \ + gen_helper_##name(t1, cpu_env, t0); \ + set_cpu_vsrh(xT(ctx->opcode), t1); \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i64(t1); \ } GEN_VSX_HELPER_2(xsadddp, 0x00, 0x04, 0, PPC2_VSX) @@ -949,76 +1139,146 @@ GEN_VSX_HELPER_2(xxpermr, 0x08, 0x07, 0, PPC2_ISA300) static void gen_xxbrd(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); - TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode)); - TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode)); + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xbh; + TCGv_i64 xbl; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xbh = tcg_temp_new_i64(); + xbl = tcg_temp_new_i64(); + get_cpu_vsrh(xbh, xB(ctx->opcode)); + get_cpu_vsrl(xbl, xB(ctx->opcode)); + tcg_gen_bswap64_i64(xth, xbh); tcg_gen_bswap64_i64(xtl, xbl); + set_cpu_vsrh(xT(ctx->opcode), xth); + set_cpu_vsrl(xT(ctx->opcode), xtl); + + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); + tcg_temp_free_i64(xbh); + tcg_temp_free_i64(xbl); } static void gen_xxbrh(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); - TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode)); - TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode)); + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xbh; + TCGv_i64 xbl; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xbh = tcg_temp_new_i64(); + xbl = tcg_temp_new_i64(); + get_cpu_vsrh(xbh, xB(ctx->opcode)); + get_cpu_vsrl(xbl, xB(ctx->opcode)); + gen_bswap16x8(xth, xtl, xbh, xbl); + set_cpu_vsrh(xT(ctx->opcode), xth); + set_cpu_vsrl(xT(ctx->opcode), xtl); + + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); + tcg_temp_free_i64(xbh); + tcg_temp_free_i64(xbl); } static void gen_xxbrq(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); - TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode)); - TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode)); - TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xbh; + TCGv_i64 xbl; + TCGv_i64 t0; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xbh = tcg_temp_new_i64(); + xbl = tcg_temp_new_i64(); + get_cpu_vsrh(xbh, xB(ctx->opcode)); + get_cpu_vsrl(xbl, xB(ctx->opcode)); + t0 = tcg_temp_new_i64(); + tcg_gen_bswap64_i64(t0, xbl); tcg_gen_bswap64_i64(xtl, xbh); + set_cpu_vsrl(xT(ctx->opcode), xtl); tcg_gen_mov_i64(xth, t0); + set_cpu_vsrl(xT(ctx->opcode), xth); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); + tcg_temp_free_i64(xbh); + tcg_temp_free_i64(xbl); } static void gen_xxbrw(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); - TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode)); - TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode)); + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xbh; + TCGv_i64 xbl; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xbh = tcg_temp_new_i64(); + xbl = tcg_temp_new_i64(); + get_cpu_vsrh(xbh, xB(ctx->opcode)); + get_cpu_vsrl(xbl, xB(ctx->opcode)); + gen_bswap32x4(xth, xtl, xbh, xbl); + set_cpu_vsrl(xT(ctx->opcode), xth); + set_cpu_vsrl(xT(ctx->opcode), xtl); + + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); + tcg_temp_free_i64(xbh); + tcg_temp_free_i64(xbl); } #define VSX_LOGICAL(name, tcg_op) \ static void glue(gen_, name)(DisasContext * ctx) \ { \ + TCGv_i64 t0; \ + TCGv_i64 t1; \ + TCGv_i64 t2; \ 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))); \ + t0 = tcg_temp_new_i64(); \ + t1 = tcg_temp_new_i64(); \ + t2 = tcg_temp_new_i64(); \ + get_cpu_vsrh(t0, xA(ctx->opcode)); \ + get_cpu_vsrh(t1, xB(ctx->opcode)); \ + tcg_op(t2, t0, t1); \ + set_cpu_vsrh(xT(ctx->opcode), t2); \ + get_cpu_vsrl(t0, xA(ctx->opcode)); \ + get_cpu_vsrl(t1, xB(ctx->opcode)); \ + tcg_op(t2, t0, t1); \ + set_cpu_vsrl(xT(ctx->opcode), t2); \ + tcg_temp_free_i64(t0); \ + tcg_temp_free_i64(t1); \ + tcg_temp_free_i64(t2); \ } VSX_LOGICAL(xxland, tcg_gen_and_i64) @@ -1033,7 +1293,7 @@ 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; \ + TCGv_i64 a0, a1, b0, b1, tmp; \ if (unlikely(!ctx->vsx_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ @@ -1042,27 +1302,29 @@ static void glue(gen_, name)(DisasContext * ctx) \ a1 = tcg_temp_new_i64(); \ b0 = tcg_temp_new_i64(); \ b1 = tcg_temp_new_i64(); \ + tmp = 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))); \ + get_cpu_vsrh(a0, xA(ctx->opcode)); \ + get_cpu_vsrh(a1, xA(ctx->opcode)); \ + get_cpu_vsrh(b0, xB(ctx->opcode)); \ + get_cpu_vsrh(b1, 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))); \ + get_cpu_vsrl(a0, xA(ctx->opcode)); \ + get_cpu_vsrl(a1, xA(ctx->opcode)); \ + get_cpu_vsrl(b0, xB(ctx->opcode)); \ + get_cpu_vsrl(b1, 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_gen_deposit_i64(tmp, b0, a0, 32, 32); \ + set_cpu_vsrh(xT(ctx->opcode), tmp); \ + tcg_gen_deposit_i64(tmp, b1, a1, 32, 32); \ + set_cpu_vsrl(xT(ctx->opcode), tmp); \ tcg_temp_free_i64(a0); \ tcg_temp_free_i64(a1); \ tcg_temp_free_i64(b0); \ tcg_temp_free_i64(b1); \ + tcg_temp_free_i64(tmp); \ } VSX_XXMRG(xxmrghw, 1) @@ -1070,7 +1332,7 @@ VSX_XXMRG(xxmrglw, 0) static void gen_xxsel(DisasContext * ctx) { - TCGv_i64 a, b, c; + TCGv_i64 a, b, c, tmp; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; @@ -1078,40 +1340,49 @@ static void gen_xxsel(DisasContext * ctx) a = tcg_temp_new_i64(); b = tcg_temp_new_i64(); c = tcg_temp_new_i64(); + tmp = 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))); + get_cpu_vsrh(a, xA(ctx->opcode)); + get_cpu_vsrh(b, xB(ctx->opcode)); + get_cpu_vsrh(c, 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_or_i64(tmp, a, b); + set_cpu_vsrh(xT(ctx->opcode), tmp); - 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))); + get_cpu_vsrl(a, xA(ctx->opcode)); + get_cpu_vsrl(b, xB(ctx->opcode)); + get_cpu_vsrl(c, 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_gen_or_i64(tmp, a, b); + set_cpu_vsrl(xT(ctx->opcode), tmp); tcg_temp_free_i64(a); tcg_temp_free_i64(b); tcg_temp_free_i64(c); + tcg_temp_free_i64(tmp); } 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)); + TCGv_i64 vsr; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + vsr = tcg_temp_new_i64(); + if (UIM(ctx->opcode) & 2) { + get_cpu_vsrl(vsr, xB(ctx->opcode)); + } else { + get_cpu_vsrh(vsr, xB(ctx->opcode)); + } + b = tcg_temp_new_i64(); b2 = tcg_temp_new_i64(); @@ -1122,9 +1393,11 @@ static void gen_xxspltw(DisasContext *ctx) } 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_gen_or_i64(vsr, b, b2); + set_cpu_vsrh(xT(ctx->opcode), vsr); + set_cpu_vsrl(xT(ctx->opcode), vsr); + tcg_temp_free_i64(vsr); tcg_temp_free_i64(b); tcg_temp_free_i64(b2); } @@ -1134,6 +1407,7 @@ static void gen_xxspltw(DisasContext *ctx) static void gen_xxspltib(DisasContext *ctx) { unsigned char uim8 = IMM8(ctx->opcode); + TCGv_i64 vsr; if (xS(ctx->opcode) < 32) { if (unlikely(!ctx->altivec_enabled)) { gen_exception(ctx, POWERPC_EXCP_VPU); @@ -1145,8 +1419,11 @@ static void gen_xxspltib(DisasContext *ctx) return; } } - tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), pattern(uim8)); - tcg_gen_movi_i64(cpu_vsrl(xT(ctx->opcode)), pattern(uim8)); + vsr = tcg_temp_new_i64(); + tcg_gen_movi_i64(vsr, pattern(uim8)); + set_cpu_vsrh(xT(ctx->opcode), vsr); + set_cpu_vsrl(xT(ctx->opcode), vsr); + tcg_temp_free_i64(vsr); } static void gen_xxsldwi(DisasContext *ctx) @@ -1161,40 +1438,40 @@ static void gen_xxsldwi(DisasContext *ctx) 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))); + get_cpu_vsrh(xth, xA(ctx->opcode)); + get_cpu_vsrl(xtl, xA(ctx->opcode)); break; } case 1: { TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode))); + get_cpu_vsrh(xth, xA(ctx->opcode)); tcg_gen_shli_i64(xth, xth, 32); - tcg_gen_mov_i64(t0, cpu_vsrl(xA(ctx->opcode))); + get_cpu_vsrl(t0, 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))); + get_cpu_vsrl(xtl, xA(ctx->opcode)); tcg_gen_shli_i64(xtl, xtl, 32); - tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode))); + get_cpu_vsrh(t0, 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))); + get_cpu_vsrl(xth, xA(ctx->opcode)); + get_cpu_vsrh(xtl, xB(ctx->opcode)); break; } case 3: { TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode))); + get_cpu_vsrl(xth, xA(ctx->opcode)); tcg_gen_shli_i64(xth, xth, 32); - tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode))); + get_cpu_vsrh(t0, 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))); + get_cpu_vsrh(xtl, xB(ctx->opcode)); tcg_gen_shli_i64(xtl, xtl, 32); - tcg_gen_mov_i64(t0, cpu_vsrl(xB(ctx->opcode))); + get_cpu_vsrl(t0, xB(ctx->opcode)); tcg_gen_shri_i64(t0, t0, 32); tcg_gen_or_i64(xtl, xtl, t0); tcg_temp_free_i64(t0); @@ -1202,8 +1479,8 @@ static void gen_xxsldwi(DisasContext *ctx) } } - tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xth); - tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xtl); + set_cpu_vsrh(xT(ctx->opcode), xth); + set_cpu_vsrl(xT(ctx->opcode), xtl); tcg_temp_free_i64(xth); tcg_temp_free_i64(xtl); @@ -1213,7 +1490,8 @@ static void gen_xxsldwi(DisasContext *ctx) static void gen_##name(DisasContext *ctx) \ { \ TCGv xt, xb; \ - TCGv_i32 t0 = tcg_temp_new_i32(); \ + TCGv_i32 t0; \ + TCGv_i64 t1; \ uint8_t uimm = UIMM4(ctx->opcode); \ \ if (unlikely(!ctx->vsx_enabled)) { \ @@ -1222,12 +1500,15 @@ static void gen_##name(DisasContext *ctx) \ } \ xt = tcg_const_tl(xT(ctx->opcode)); \ xb = tcg_const_tl(xB(ctx->opcode)); \ + t0 = tcg_temp_new_i32(); \ + t1 = tcg_temp_new_i64(); \ /* uimm > 15 out of bound and for \ * uimm > 12 handle as per hardware in helper \ */ \ if (uimm > 15) { \ - tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), 0); \ - tcg_gen_movi_i64(cpu_vsrl(xT(ctx->opcode)), 0); \ + tcg_gen_movi_i64(t1, 0); \ + set_cpu_vsrh(xT(ctx->opcode), t1); \ + set_cpu_vsrl(xT(ctx->opcode), t1); \ return; \ } \ tcg_gen_movi_i32(t0, uimm); \ @@ -1235,6 +1516,7 @@ static void gen_##name(DisasContext *ctx) \ tcg_temp_free(xb); \ tcg_temp_free(xt); \ tcg_temp_free_i32(t0); \ + tcg_temp_free_i64(t1); \ } VSX_EXTRACT_INSERT(xxextractuw) @@ -1244,30 +1526,45 @@ VSX_EXTRACT_INSERT(xxinsertw) static void gen_xsxexpdp(DisasContext *ctx) { TCGv rt = cpu_gpr[rD(ctx->opcode)]; + TCGv_i64 t0; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } - tcg_gen_extract_i64(rt, cpu_vsrh(xB(ctx->opcode)), 52, 11); + t0 = tcg_temp_new_i64(); + get_cpu_vsrh(t0, xB(ctx->opcode)); + tcg_gen_extract_i64(rt, t0, 52, 11); + tcg_temp_free_i64(t0); } static void gen_xsxexpqp(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32); - TCGv_i64 xtl = cpu_vsrl(rD(ctx->opcode) + 32); - TCGv_i64 xbh = cpu_vsrh(rB(ctx->opcode) + 32); + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xbh; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xbh = tcg_temp_new_i64(); + get_cpu_vsrh(xbh, rB(ctx->opcode) + 32); + tcg_gen_extract_i64(xth, xbh, 48, 15); + set_cpu_vsrh(rD(ctx->opcode) + 32, xth); tcg_gen_movi_i64(xtl, 0); + set_cpu_vsrl(rD(ctx->opcode) + 32, xtl); + + tcg_temp_free_i64(xbh); + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); } static void gen_xsiexpdp(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); + TCGv_i64 xth; TCGv ra = cpu_gpr[rA(ctx->opcode)]; TCGv rb = cpu_gpr[rB(ctx->opcode)]; TCGv_i64 t0; @@ -1277,40 +1574,60 @@ static void gen_xsiexpdp(DisasContext *ctx) return; } t0 = tcg_temp_new_i64(); + xth = tcg_temp_new_i64(); tcg_gen_andi_i64(xth, ra, 0x800FFFFFFFFFFFFF); tcg_gen_andi_i64(t0, rb, 0x7FF); tcg_gen_shli_i64(t0, t0, 52); tcg_gen_or_i64(xth, xth, t0); + set_cpu_vsrh(xT(ctx->opcode), xth); /* dword[1] is undefined */ tcg_temp_free_i64(t0); + tcg_temp_free_i64(xth); } static void gen_xsiexpqp(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32); - TCGv_i64 xtl = cpu_vsrl(rD(ctx->opcode) + 32); - TCGv_i64 xah = cpu_vsrh(rA(ctx->opcode) + 32); - TCGv_i64 xal = cpu_vsrl(rA(ctx->opcode) + 32); - TCGv_i64 xbh = cpu_vsrh(rB(ctx->opcode) + 32); + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xah; + TCGv_i64 xal; + TCGv_i64 xbh; TCGv_i64 t0; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xah = tcg_temp_new_i64(); + xal = tcg_temp_new_i64(); + get_cpu_vsrh(xah, rA(ctx->opcode) + 32); + get_cpu_vsrl(xal, rA(ctx->opcode) + 32); + xbh = tcg_temp_new_i64(); + get_cpu_vsrh(xbh, rB(ctx->opcode) + 32); t0 = tcg_temp_new_i64(); + tcg_gen_andi_i64(xth, xah, 0x8000FFFFFFFFFFFF); tcg_gen_andi_i64(t0, xbh, 0x7FFF); tcg_gen_shli_i64(t0, t0, 48); tcg_gen_or_i64(xth, xth, t0); + set_cpu_vsrh(rD(ctx->opcode) + 32, xth); tcg_gen_mov_i64(xtl, xal); + set_cpu_vsrl(rD(ctx->opcode) + 32, xtl); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); + tcg_temp_free_i64(xah); + tcg_temp_free_i64(xal); + tcg_temp_free_i64(xbh); } static void gen_xsxsigdp(DisasContext *ctx) { TCGv rt = cpu_gpr[rD(ctx->opcode)]; - TCGv_i64 t0, zr, nan, exp; + TCGv_i64 t0, t1, zr, nan, exp; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); @@ -1318,17 +1635,21 @@ static void gen_xsxsigdp(DisasContext *ctx) } exp = tcg_temp_new_i64(); t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); zr = tcg_const_i64(0); nan = tcg_const_i64(2047); - tcg_gen_extract_i64(exp, cpu_vsrh(xB(ctx->opcode)), 52, 11); + get_cpu_vsrh(t1, xB(ctx->opcode)); + tcg_gen_extract_i64(exp, t1, 52, 11); tcg_gen_movi_i64(t0, 0x0010000000000000); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0); - tcg_gen_andi_i64(rt, cpu_vsrh(xB(ctx->opcode)), 0x000FFFFFFFFFFFFF); + get_cpu_vsrh(t1, xB(ctx->opcode)); + tcg_gen_andi_i64(rt, t1, 0x000FFFFFFFFFFFFF); tcg_gen_or_i64(rt, rt, t0); tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); tcg_temp_free_i64(exp); tcg_temp_free_i64(zr); tcg_temp_free_i64(nan); @@ -1337,132 +1658,219 @@ static void gen_xsxsigdp(DisasContext *ctx) static void gen_xsxsigqp(DisasContext *ctx) { TCGv_i64 t0, zr, nan, exp; - TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32); - TCGv_i64 xtl = cpu_vsrl(rD(ctx->opcode) + 32); + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xbh; + TCGv_i64 xbl; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xbh = tcg_temp_new_i64(); + xbl = tcg_temp_new_i64(); + get_cpu_vsrh(xbh, rB(ctx->opcode) + 32); + get_cpu_vsrl(xbl, rB(ctx->opcode) + 32); exp = tcg_temp_new_i64(); t0 = tcg_temp_new_i64(); zr = tcg_const_i64(0); nan = tcg_const_i64(32767); - tcg_gen_extract_i64(exp, cpu_vsrh(rB(ctx->opcode) + 32), 48, 15); + tcg_gen_extract_i64(exp, xbh, 48, 15); tcg_gen_movi_i64(t0, 0x0001000000000000); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0); - tcg_gen_andi_i64(xth, cpu_vsrh(rB(ctx->opcode) + 32), 0x0000FFFFFFFFFFFF); + tcg_gen_andi_i64(xth, xbh, 0x0000FFFFFFFFFFFF); tcg_gen_or_i64(xth, xth, t0); - tcg_gen_mov_i64(xtl, cpu_vsrl(rB(ctx->opcode) + 32)); + set_cpu_vsrh(rD(ctx->opcode) + 32, xth); + tcg_gen_mov_i64(xtl, xbl); + set_cpu_vsrl(rD(ctx->opcode) + 32, xtl); tcg_temp_free_i64(t0); tcg_temp_free_i64(exp); tcg_temp_free_i64(zr); tcg_temp_free_i64(nan); + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); + tcg_temp_free_i64(xbh); + tcg_temp_free_i64(xbl); } #endif static void gen_xviexpsp(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); - TCGv_i64 xah = cpu_vsrh(xA(ctx->opcode)); - TCGv_i64 xal = cpu_vsrl(xA(ctx->opcode)); - TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode)); - TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode)); + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xah; + TCGv_i64 xal; + TCGv_i64 xbh; + TCGv_i64 xbl; TCGv_i64 t0; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xah = tcg_temp_new_i64(); + xal = tcg_temp_new_i64(); + xbh = tcg_temp_new_i64(); + xbl = tcg_temp_new_i64(); + get_cpu_vsrh(xah, xA(ctx->opcode)); + get_cpu_vsrl(xal, xA(ctx->opcode)); + get_cpu_vsrh(xbh, xB(ctx->opcode)); + get_cpu_vsrl(xbl, xB(ctx->opcode)); t0 = tcg_temp_new_i64(); + tcg_gen_andi_i64(xth, xah, 0x807FFFFF807FFFFF); tcg_gen_andi_i64(t0, xbh, 0xFF000000FF); tcg_gen_shli_i64(t0, t0, 23); tcg_gen_or_i64(xth, xth, t0); + set_cpu_vsrh(xT(ctx->opcode), xth); tcg_gen_andi_i64(xtl, xal, 0x807FFFFF807FFFFF); tcg_gen_andi_i64(t0, xbl, 0xFF000000FF); tcg_gen_shli_i64(t0, t0, 23); tcg_gen_or_i64(xtl, xtl, t0); + set_cpu_vsrl(xT(ctx->opcode), xtl); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); + tcg_temp_free_i64(xah); + tcg_temp_free_i64(xal); + tcg_temp_free_i64(xbh); + tcg_temp_free_i64(xbl); } static void gen_xviexpdp(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); - TCGv_i64 xah = cpu_vsrh(xA(ctx->opcode)); - TCGv_i64 xal = cpu_vsrl(xA(ctx->opcode)); - TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode)); - TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode)); + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xah; + TCGv_i64 xal; + TCGv_i64 xbh; + TCGv_i64 xbl; TCGv_i64 t0; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xah = tcg_temp_new_i64(); + xal = tcg_temp_new_i64(); + xbh = tcg_temp_new_i64(); + xbl = tcg_temp_new_i64(); + get_cpu_vsrh(xah, xA(ctx->opcode)); + get_cpu_vsrl(xal, xA(ctx->opcode)); + get_cpu_vsrh(xbh, xB(ctx->opcode)); + get_cpu_vsrl(xbl, xB(ctx->opcode)); t0 = tcg_temp_new_i64(); + tcg_gen_andi_i64(xth, xah, 0x800FFFFFFFFFFFFF); tcg_gen_andi_i64(t0, xbh, 0x7FF); tcg_gen_shli_i64(t0, t0, 52); tcg_gen_or_i64(xth, xth, t0); + set_cpu_vsrh(xT(ctx->opcode), xth); tcg_gen_andi_i64(xtl, xal, 0x800FFFFFFFFFFFFF); tcg_gen_andi_i64(t0, xbl, 0x7FF); tcg_gen_shli_i64(t0, t0, 52); tcg_gen_or_i64(xtl, xtl, t0); + set_cpu_vsrl(xT(ctx->opcode), xtl); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); + tcg_temp_free_i64(xah); + tcg_temp_free_i64(xal); + tcg_temp_free_i64(xbh); + tcg_temp_free_i64(xbl); } static void gen_xvxexpsp(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); - TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode)); - TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode)); + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xbh; + TCGv_i64 xbl; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xbh = tcg_temp_new_i64(); + xbl = tcg_temp_new_i64(); + get_cpu_vsrh(xbh, xB(ctx->opcode)); + get_cpu_vsrl(xbl, xB(ctx->opcode)); + tcg_gen_shri_i64(xth, xbh, 23); tcg_gen_andi_i64(xth, xth, 0xFF000000FF); + set_cpu_vsrh(xT(ctx->opcode), xth); tcg_gen_shri_i64(xtl, xbl, 23); tcg_gen_andi_i64(xtl, xtl, 0xFF000000FF); + set_cpu_vsrl(xT(ctx->opcode), xtl); + + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); + tcg_temp_free_i64(xbh); + tcg_temp_free_i64(xbl); } static void gen_xvxexpdp(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); - TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode)); - TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode)); + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xbh; + TCGv_i64 xbl; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xbh = tcg_temp_new_i64(); + xbl = tcg_temp_new_i64(); + get_cpu_vsrh(xbh, xB(ctx->opcode)); + get_cpu_vsrl(xbl, xB(ctx->opcode)); + tcg_gen_extract_i64(xth, xbh, 52, 11); + set_cpu_vsrh(xT(ctx->opcode), xth); tcg_gen_extract_i64(xtl, xbl, 52, 11); + set_cpu_vsrl(xT(ctx->opcode), xtl); + + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); + tcg_temp_free_i64(xbh); + tcg_temp_free_i64(xbl); } GEN_VSX_HELPER_2(xvxsigsp, 0x00, 0x04, 0, PPC2_ISA300) static void gen_xvxsigdp(DisasContext *ctx) { - TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); - TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); - TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode)); - TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode)); - + TCGv_i64 xth; + TCGv_i64 xtl; + TCGv_i64 xbh; + TCGv_i64 xbl; TCGv_i64 t0, zr, nan, exp; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); return; } + xth = tcg_temp_new_i64(); + xtl = tcg_temp_new_i64(); + xbh = tcg_temp_new_i64(); + xbl = tcg_temp_new_i64(); + get_cpu_vsrh(xbh, xB(ctx->opcode)); + get_cpu_vsrl(xbl, xB(ctx->opcode)); exp = tcg_temp_new_i64(); t0 = tcg_temp_new_i64(); zr = tcg_const_i64(0); @@ -1474,6 +1882,7 @@ static void gen_xvxsigdp(DisasContext *ctx) tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0); tcg_gen_andi_i64(xth, xbh, 0x000FFFFFFFFFFFFF); tcg_gen_or_i64(xth, xth, t0); + set_cpu_vsrh(xT(ctx->opcode), xth); tcg_gen_extract_i64(exp, xbl, 52, 11); tcg_gen_movi_i64(t0, 0x0010000000000000); @@ -1481,11 +1890,16 @@ static void gen_xvxsigdp(DisasContext *ctx) tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0); tcg_gen_andi_i64(xtl, xbl, 0x000FFFFFFFFFFFFF); tcg_gen_or_i64(xtl, xtl, t0); + set_cpu_vsrl(xT(ctx->opcode), xtl); tcg_temp_free_i64(t0); tcg_temp_free_i64(exp); tcg_temp_free_i64(zr); tcg_temp_free_i64(nan); + tcg_temp_free_i64(xth); + tcg_temp_free_i64(xtl); + tcg_temp_free_i64(xbh); + tcg_temp_free_i64(xbl); } #undef GEN_XX2FORM From 7329fb6240c689648ad89b71250411b4e46f6de7 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 2 Jan 2019 09:14:20 +0000 Subject: [PATCH 10/29] target/ppc: switch FPR, VMX and VSX helpers to access data directly from cpu_env Instead of accessing the FPR, VMX and VSX registers through static arrays of TCGv_i64 globals, remove them and change the helpers to load/store data directly within cpu_env. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Acked-by: David Gibson Signed-off-by: David Gibson --- target/ppc/translate.c | 59 ++++++++--------------------- target/ppc/translate/vsx-impl.inc.c | 4 +- 2 files changed, 18 insertions(+), 45 deletions(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 3bb24e7310..b18ded07b3 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -55,15 +55,9 @@ /* global register indexes */ static char cpu_reg_names[10*3 + 22*4 /* GPR */ + 10*4 + 22*5 /* SPE GPRh */ - + 10*4 + 22*5 /* FPR */ - + 2*(10*6 + 22*7) /* AVRh, AVRl */ - + 10*5 + 22*6 /* VSR */ + 8*5 /* CRF */]; static TCGv cpu_gpr[32]; static TCGv cpu_gprh[32]; -static TCGv_i64 cpu_fpr[32]; -static TCGv_i64 cpu_avrh[32], cpu_avrl[32]; -static TCGv_i64 cpu_vsr[32]; static TCGv_i32 cpu_crf[8]; static TCGv cpu_nip; static TCGv cpu_msr; @@ -108,39 +102,6 @@ void ppc_translate_init(void) offsetof(CPUPPCState, gprh[i]), p); p += (i < 10) ? 4 : 5; cpu_reg_names_size -= (i < 10) ? 4 : 5; - - snprintf(p, cpu_reg_names_size, "fp%d", i); - cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUPPCState, fpr[i]), p); - p += (i < 10) ? 4 : 5; - cpu_reg_names_size -= (i < 10) ? 4 : 5; - - snprintf(p, cpu_reg_names_size, "avr%dH", i); -#ifdef HOST_WORDS_BIGENDIAN - cpu_avrh[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUPPCState, avr[i].u64[0]), p); -#else - cpu_avrh[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUPPCState, avr[i].u64[1]), p); -#endif - p += (i < 10) ? 6 : 7; - cpu_reg_names_size -= (i < 10) ? 6 : 7; - - snprintf(p, cpu_reg_names_size, "avr%dL", i); -#ifdef HOST_WORDS_BIGENDIAN - cpu_avrl[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUPPCState, avr[i].u64[1]), p); -#else - cpu_avrl[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUPPCState, avr[i].u64[0]), p); -#endif - p += (i < 10) ? 6 : 7; - cpu_reg_names_size -= (i < 10) ? 6 : 7; - snprintf(p, cpu_reg_names_size, "vsr%d", i); - cpu_vsr[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUPPCState, vsr[i]), p); - p += (i < 10) ? 5 : 6; - cpu_reg_names_size -= (i < 10) ? 5 : 6; } cpu_nip = tcg_global_mem_new(cpu_env, @@ -6701,22 +6662,34 @@ GEN_TM_PRIV_NOOP(trechkpt); static inline void get_fpr(TCGv_i64 dst, int regno) { - tcg_gen_mov_i64(dst, cpu_fpr[regno]); + tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, fpr[regno])); } static inline void set_fpr(int regno, TCGv_i64 src) { - tcg_gen_mov_i64(cpu_fpr[regno], src); + tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, fpr[regno])); } static inline void get_avr64(TCGv_i64 dst, int regno, bool high) { - tcg_gen_mov_i64(dst, (high ? cpu_avrh : cpu_avrl)[regno]); +#ifdef HOST_WORDS_BIGENDIAN + tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, + avr[regno].u64[(high ? 0 : 1)])); +#else + tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, + avr[regno].u64[(high ? 1 : 0)])); +#endif } static inline void set_avr64(int regno, TCGv_i64 src, bool high) { - tcg_gen_mov_i64((high ? cpu_avrh : cpu_avrl)[regno], src); +#ifdef HOST_WORDS_BIGENDIAN + tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, + avr[regno].u64[(high ? 0 : 1)])); +#else + tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, + avr[regno].u64[(high ? 1 : 0)])); +#endif } #include "translate/fp-impl.inc.c" diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c index f0665df1a5..7eaa36b4d5 100644 --- a/target/ppc/translate/vsx-impl.inc.c +++ b/target/ppc/translate/vsx-impl.inc.c @@ -2,12 +2,12 @@ static inline void get_vsr(TCGv_i64 dst, int n) { - tcg_gen_mov_i64(dst, cpu_vsr[n]); + tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, vsr[n])); } static inline void set_vsr(int n, TCGv_i64 src) { - tcg_gen_mov_i64(cpu_vsr[n], src); + tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, vsr[n])); } static inline void get_cpu_vsrh(TCGv_i64 dst, int n) From 05ee3e8aa0c0178e98c9a05755359e382f56ce87 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 2 Jan 2019 09:14:21 +0000 Subject: [PATCH 11/29] target/ppc: merge ppc_vsr_t and ppc_avr_t union types Since the VSX registers are actually a superset of the VMX registers then they can be represented by the same type. Merge ppc_avr_t into ppc_vsr_t and change ppc_avr_t to be a simple typedef alias. Note that due to a difference in the naming of the float32 member between ppc_avr_t and ppc_vsr_t, references to the ppc_avr_t f member must be replaced with f32 instead. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Acked-by: David Gibson Signed-off-by: David Gibson --- target/ppc/cpu.h | 17 +++++++------ target/ppc/int_helper.c | 56 +++++++++++++++++++++-------------------- target/ppc/internal.h | 11 -------- 3 files changed, 39 insertions(+), 45 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index d5f99f1fc7..578641ac20 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -218,7 +218,6 @@ typedef struct opc_handler_t opc_handler_t; /* Types used to describe some PowerPC registers etc. */ typedef struct DisasContext DisasContext; typedef struct ppc_spr_t ppc_spr_t; -typedef union ppc_avr_t ppc_avr_t; typedef union ppc_tlb_t ppc_tlb_t; typedef struct ppc_hash_pte64 ppc_hash_pte64_t; @@ -242,22 +241,26 @@ struct ppc_spr_t { #endif }; -/* Altivec registers (128 bits) */ -union ppc_avr_t { - float32 f[4]; +/* VSX/Altivec registers (128 bits) */ +typedef union _ppc_vsr_t { uint8_t u8[16]; uint16_t u16[8]; uint32_t u32[4]; + uint64_t u64[2]; int8_t s8[16]; int16_t s16[8]; int32_t s32[4]; - uint64_t u64[2]; int64_t s64[2]; + float32 f32[4]; + float64 f64[2]; + float128 f128; #ifdef CONFIG_INT128 __uint128_t u128; #endif - Int128 s128; -}; + Int128 s128; +} ppc_vsr_t; + +typedef ppc_vsr_t ppc_avr_t; #if !defined(CONFIG_USER_ONLY) /* Software TLB cache */ diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index fcac90a4a9..9d715be25c 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -548,8 +548,8 @@ VARITH_DO(muluwm, *, u32) { \ int i; \ \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \ + for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \ + r->f32[i] = func(a->f32[i], b->f32[i], &env->vec_status); \ } \ } VARITHFP(addfp, float32_add) @@ -563,9 +563,9 @@ VARITHFP(maxfp, float32_max) ppc_avr_t *b, ppc_avr_t *c) \ { \ int i; \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - r->f[i] = float32_muladd(a->f[i], c->f[i], b->f[i], \ - type, &env->vec_status); \ + for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \ + r->f32[i] = float32_muladd(a->f32[i], c->f32[i], b->f32[i], \ + type, &env->vec_status); \ } \ } VARITHFPFMA(maddfp, 0); @@ -670,9 +670,9 @@ VABSDU(w, u32) { \ int i; \ \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ + for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \ float32 t = cvt(b->element[i], &env->vec_status); \ - r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \ + r->f32[i] = float32_scalbn(t, -uim, &env->vec_status); \ } \ } VCF(ux, uint32_to_float32, u32) @@ -782,9 +782,9 @@ VCMPNE(w, u32, uint32_t, 0) uint32_t none = 0; \ int i; \ \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ + for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \ uint32_t result; \ - int rel = float32_compare_quiet(a->f[i], b->f[i], \ + int rel = float32_compare_quiet(a->f32[i], b->f32[i], \ &env->vec_status); \ if (rel == float_relation_unordered) { \ result = 0; \ @@ -816,14 +816,16 @@ static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r, int i; int all_in = 0; - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); + for (i = 0; i < ARRAY_SIZE(r->f32); i++) { + int le_rel = float32_compare_quiet(a->f32[i], b->f32[i], + &env->vec_status); if (le_rel == float_relation_unordered) { r->u32[i] = 0xc0000000; all_in = 1; } else { - float32 bneg = float32_chs(b->f[i]); - int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status); + float32 bneg = float32_chs(b->f32[i]); + int ge_rel = float32_compare_quiet(a->f32[i], bneg, + &env->vec_status); int le = le_rel != float_relation_greater; int ge = ge_rel != float_relation_less; @@ -856,11 +858,11 @@ void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, float_status s = env->vec_status; \ \ set_float_rounding_mode(float_round_to_zero, &s); \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - if (float32_is_any_nan(b->f[i])) { \ + for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \ + if (float32_is_any_nan(b->f32[i])) { \ r->element[i] = 0; \ } else { \ - float64 t = float32_to_float64(b->f[i], &s); \ + float64 t = float32_to_float64(b->f32[i], &s); \ int64_t j; \ \ t = float64_scalbn(t, uim, &s); \ @@ -1661,8 +1663,8 @@ void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) { int i; - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status); + for (i = 0; i < ARRAY_SIZE(r->f32); i++) { + r->f32[i] = float32_div(float32_one, b->f32[i], &env->vec_status); } } @@ -1674,8 +1676,8 @@ void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) float_status s = env->vec_status; \ \ set_float_rounding_mode(rounding, &s); \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - r->f[i] = float32_round_to_int (b->f[i], &s); \ + for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \ + r->f32[i] = float32_round_to_int (b->f32[i], &s); \ } \ } VRFI(n, float_round_nearest_even) @@ -1705,10 +1707,10 @@ void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) { int i; - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - float32 t = float32_sqrt(b->f[i], &env->vec_status); + for (i = 0; i < ARRAY_SIZE(r->f32); i++) { + float32 t = float32_sqrt(b->f32[i], &env->vec_status); - r->f[i] = float32_div(float32_one, t, &env->vec_status); + r->f32[i] = float32_div(float32_one, t, &env->vec_status); } } @@ -1751,8 +1753,8 @@ void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) { int i; - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - r->f[i] = float32_exp2(b->f[i], &env->vec_status); + for (i = 0; i < ARRAY_SIZE(r->f32); i++) { + r->f32[i] = float32_exp2(b->f32[i], &env->vec_status); } } @@ -1760,8 +1762,8 @@ void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) { int i; - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - r->f[i] = float32_log2(b->f[i], &env->vec_status); + for (i = 0; i < ARRAY_SIZE(r->f32); i++) { + r->f32[i] = float32_log2(b->f32[i], &env->vec_status); } } diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 5d460247e2..bd247f2504 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -204,17 +204,6 @@ EXTRACT_HELPER(IMM8, 11, 8); EXTRACT_HELPER(DCMX, 16, 7); EXTRACT_HELPER_SPLIT_3(DCMX_XV, 5, 16, 0, 1, 2, 5, 1, 6, 6); -typedef union _ppc_vsr_t { - uint8_t u8[16]; - uint16_t u16[8]; - uint32_t u32[4]; - uint64_t u64[2]; - float32 f32[4]; - float64 f64[2]; - float128 f128; - Int128 s128; -} ppc_vsr_t; - #if defined(HOST_WORDS_BIGENDIAN) #define VsrB(i) u8[i] #define VsrH(i) u16[i] From ef96e3ae9698d6726a8113f448c82985a9f31ff5 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 2 Jan 2019 09:14:22 +0000 Subject: [PATCH 12/29] target/ppc: move FP and VMX registers into aligned vsr register array The VSX register array is a block of 64 128-bit registers where the first 32 registers consist of the existing 64-bit FP registers extended to 128-bit using new VSR registers, and the last 32 registers are the VMX 128-bit registers as show below: 64-bit 64-bit +--------------------+--------------------+ | FP0 | | VSR0 +--------------------+--------------------+ | FP1 | | VSR1 +--------------------+--------------------+ | ... | ... | ... +--------------------+--------------------+ | FP30 | | VSR30 +--------------------+--------------------+ | FP31 | | VSR31 +--------------------+--------------------+ | VMX0 | VSR32 +-----------------------------------------+ | VMX1 | VSR33 +-----------------------------------------+ | ... | ... +-----------------------------------------+ | VMX30 | VSR62 +-----------------------------------------+ | VMX31 | VSR63 +-----------------------------------------+ In order to allow for future conversion of VSX instructions to use TCG vector operations, recreate the same layout using an aligned version of the existing vsr register array. Since the old fpr and avr register arrays are removed, the existing callers must also be updated to use the correct offset in the vsr register array. This also includes switching the relevant VMState fields over to using subarrays to make sure that migration is preserved. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Acked-by: David Gibson Signed-off-by: David Gibson --- linux-user/ppc/signal.c | 28 ++++++----- target/ppc/arch_dump.c | 15 +++--- target/ppc/cpu.h | 25 +++++++--- target/ppc/gdbstub.c | 8 ++-- target/ppc/internal.h | 18 ++------ target/ppc/kvm.c | 24 ++++++---- target/ppc/machine.c | 72 +++++++++++++++++++++++++++-- target/ppc/monitor.c | 4 +- target/ppc/translate.c | 14 +++--- target/ppc/translate/dfp-impl.inc.c | 2 +- target/ppc/translate/vmx-impl.inc.c | 7 ++- target/ppc/translate/vsx-impl.inc.c | 4 +- target/ppc/translate_init.inc.c | 26 ++++++----- 13 files changed, 165 insertions(+), 82 deletions(-) diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index 2ae120a2bc..619a56950d 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -258,8 +258,8 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) /* Save Altivec registers if necessary. */ if (env->insns_flags & PPC_ALTIVEC) { uint32_t *vrsave; - for (i = 0; i < ARRAY_SIZE(env->avr); i++) { - ppc_avr_t *avr = &env->avr[i]; + for (i = 0; i < 32; i++) { + ppc_avr_t *avr = cpu_avr_ptr(env, i); ppc_avr_t *vreg = (ppc_avr_t *)&frame->mc_vregs.altivec[i]; __put_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]); @@ -281,15 +281,17 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) /* Save VSX second halves */ if (env->insns_flags2 & PPC2_VSX) { uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34]; - for (i = 0; i < ARRAY_SIZE(env->vsr); i++) { - __put_user(env->vsr[i], &vsregs[i]); + for (i = 0; i < 32; i++) { + uint64_t *vsrl = cpu_vsrl_ptr(env, i); + __put_user(*vsrl, &vsregs[i]); } } /* Save floating point registers. */ if (env->insns_flags & PPC_FLOAT) { - for (i = 0; i < ARRAY_SIZE(env->fpr); i++) { - __put_user(env->fpr[i], &frame->mc_fregs[i]); + for (i = 0; i < 32; i++) { + uint64_t *fpr = cpu_fpr_ptr(env, i); + __put_user(*fpr, &frame->mc_fregs[i]); } __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]); } @@ -373,8 +375,8 @@ static void restore_user_regs(CPUPPCState *env, #else v_regs = (ppc_avr_t *)frame->mc_vregs.altivec; #endif - for (i = 0; i < ARRAY_SIZE(env->avr); i++) { - ppc_avr_t *avr = &env->avr[i]; + for (i = 0; i < 32; i++) { + ppc_avr_t *avr = cpu_avr_ptr(env, i); ppc_avr_t *vreg = &v_regs[i]; __get_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]); @@ -393,16 +395,18 @@ static void restore_user_regs(CPUPPCState *env, /* Restore VSX second halves */ if (env->insns_flags2 & PPC2_VSX) { uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34]; - for (i = 0; i < ARRAY_SIZE(env->vsr); i++) { - __get_user(env->vsr[i], &vsregs[i]); + for (i = 0; i < 32; i++) { + uint64_t *vsrl = cpu_vsrl_ptr(env, i); + __get_user(*vsrl, &vsregs[i]); } } /* Restore floating point registers. */ if (env->insns_flags & PPC_FLOAT) { uint64_t fpscr; - for (i = 0; i < ARRAY_SIZE(env->fpr); i++) { - __get_user(env->fpr[i], &frame->mc_fregs[i]); + for (i = 0; i < 32; i++) { + uint64_t *fpr = cpu_fpr_ptr(env, i); + __get_user(*fpr, &frame->mc_fregs[i]); } __get_user(fpscr, &frame->mc_fregs[32]); env->fpscr = (uint32_t) fpscr; diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c index cc1460e4e3..3a00606d01 100644 --- a/target/ppc/arch_dump.c +++ b/target/ppc/arch_dump.c @@ -140,7 +140,8 @@ static void ppc_write_elf_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu) memset(fpregset, 0, sizeof(*fpregset)); for (i = 0; i < 32; i++) { - fpregset->fpr[i] = cpu_to_dump64(s, cpu->env.fpr[i]); + uint64_t *fpr = cpu_fpr_ptr(&cpu->env, i); + fpregset->fpr[i] = cpu_to_dump64(s, *fpr); } fpregset->fpscr = cpu_to_dump_reg(s, cpu->env.fpscr); } @@ -158,6 +159,7 @@ static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu) for (i = 0; i < 32; i++) { bool needs_byteswap; + ppc_avr_t *avr = cpu_avr_ptr(&cpu->env, i); #ifdef HOST_WORDS_BIGENDIAN needs_byteswap = s->dump_info.d_endian == ELFDATA2LSB; @@ -166,11 +168,11 @@ static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu) #endif if (needs_byteswap) { - vmxregset->avr[i].u64[0] = bswap64(cpu->env.avr[i].u64[1]); - vmxregset->avr[i].u64[1] = bswap64(cpu->env.avr[i].u64[0]); + vmxregset->avr[i].u64[0] = bswap64(avr->u64[1]); + vmxregset->avr[i].u64[1] = bswap64(avr->u64[0]); } else { - vmxregset->avr[i].u64[0] = cpu->env.avr[i].u64[0]; - vmxregset->avr[i].u64[1] = cpu->env.avr[i].u64[1]; + vmxregset->avr[i].u64[0] = avr->u64[0]; + vmxregset->avr[i].u64[1] = avr->u64[1]; } } vmxregset->vscr.u32[3] = cpu_to_dump32(s, cpu->env.vscr); @@ -188,7 +190,8 @@ static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu) memset(vsxregset, 0, sizeof(*vsxregset)); for (i = 0; i < 32; i++) { - vsxregset->vsr[i] = cpu_to_dump64(s, cpu->env.vsr[i]); + uint64_t *vsrl = cpu_vsrl_ptr(&cpu->env, i); + vsxregset->vsr[i] = cpu_to_dump64(s, *vsrl); } } diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 578641ac20..91951d7730 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1004,8 +1004,6 @@ struct CPUPPCState { /* Floating point execution context */ float_status fp_status; - /* floating point registers */ - float64 fpr[32]; /* floating point status and control register */ target_ulong fpscr; @@ -1055,11 +1053,10 @@ struct CPUPPCState { /* Special purpose registers */ target_ulong spr[1024]; ppc_spr_t spr_cb[1024]; - /* Altivec registers */ - ppc_avr_t avr[32]; + /* Vector status and control register */ uint32_t vscr; - /* VSX registers */ - uint64_t vsr[32]; + /* VSX registers (including FP and AVR) */ + ppc_vsr_t vsr[64] QEMU_ALIGNED(16); /* SPE registers */ uint64_t spe_acc; uint32_t spe_fscr; @@ -2540,6 +2537,22 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx) (start + nregs > 32 && (rx >= start || rx < start + nregs - 32)); } +/* Accessors for FP, VMX and VSX registers */ +static inline uint64_t *cpu_fpr_ptr(CPUPPCState *env, int i) +{ + return &env->vsr[i].u64[0]; +} + +static inline uint64_t *cpu_vsrl_ptr(CPUPPCState *env, int i) +{ + return &env->vsr[i].u64[1]; +} + +static inline ppc_avr_t *cpu_avr_ptr(CPUPPCState *env, int i) +{ + return &env->vsr[32 + i]; +} + void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env); void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len); diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index b6f6693583..19565b584d 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -126,7 +126,7 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) gdb_get_regl(mem_buf, env->gpr[n]); } else if (n < 64) { /* fprs */ - stfq_p(mem_buf, env->fpr[n-32]); + stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32)); } else { switch (n) { case 64: @@ -178,7 +178,7 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n) gdb_get_reg64(mem_buf, env->gpr[n]); } else if (n < 64) { /* fprs */ - stfq_p(mem_buf, env->fpr[n-32]); + stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32)); } else if (n < 96) { /* Altivec */ stq_p(mem_buf, n - 64); @@ -234,7 +234,7 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->gpr[n] = ldtul_p(mem_buf); } else if (n < 64) { /* fprs */ - env->fpr[n-32] = ldfq_p(mem_buf); + *cpu_fpr_ptr(env, n - 32) = ldfq_p(mem_buf); } else { switch (n) { case 64: @@ -284,7 +284,7 @@ int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n) env->gpr[n] = ldq_p(mem_buf); } else if (n < 64) { /* fprs */ - env->fpr[n-32] = ldfq_p(mem_buf); + *cpu_fpr_ptr(env, n - 32) = ldfq_p(mem_buf); } else { switch (n) { case 64 + 32: diff --git a/target/ppc/internal.h b/target/ppc/internal.h index bd247f2504..c7c0f77dd6 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -218,24 +218,14 @@ EXTRACT_HELPER_SPLIT_3(DCMX_XV, 5, 16, 0, 1, 2, 5, 1, 6, 6); static inline void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env) { - if (n < 32) { - vsr->VsrD(0) = env->fpr[n]; - vsr->VsrD(1) = env->vsr[n]; - } else { - vsr->u64[0] = env->avr[n - 32].u64[0]; - vsr->u64[1] = env->avr[n - 32].u64[1]; - } + vsr->VsrD(0) = env->vsr[n].u64[0]; + vsr->VsrD(1) = env->vsr[n].u64[1]; } static inline void putVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env) { - if (n < 32) { - env->fpr[n] = vsr->VsrD(0); - env->vsr[n] = vsr->VsrD(1); - } else { - env->avr[n - 32].u64[0] = vsr->u64[0]; - env->avr[n - 32].u64[1] = vsr->u64[1]; - } + env->vsr[n].u64[0] = vsr->VsrD(0); + env->vsr[n].u64[1] = vsr->VsrD(1); } void helper_compute_fprf_float16(CPUPPCState *env, float16 arg); diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index f81327d6cd..ebbb48c42f 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -629,13 +629,15 @@ static int kvm_put_fp(CPUState *cs) for (i = 0; i < 32; i++) { uint64_t vsr[2]; + uint64_t *fpr = cpu_fpr_ptr(&cpu->env, i); + uint64_t *vsrl = cpu_vsrl_ptr(&cpu->env, i); #ifdef HOST_WORDS_BIGENDIAN - vsr[0] = float64_val(env->fpr[i]); - vsr[1] = env->vsr[i]; + vsr[0] = float64_val(*fpr); + vsr[1] = *vsrl; #else - vsr[0] = env->vsr[i]; - vsr[1] = float64_val(env->fpr[i]); + vsr[0] = *vsrl; + vsr[1] = float64_val(*fpr); #endif reg.addr = (uintptr_t) &vsr; reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i); @@ -660,7 +662,7 @@ static int kvm_put_fp(CPUState *cs) for (i = 0; i < 32; i++) { reg.id = KVM_REG_PPC_VR(i); - reg.addr = (uintptr_t)&env->avr[i]; + reg.addr = (uintptr_t)cpu_avr_ptr(env, i); ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { DPRINTF("Unable to set VR%d to KVM: %s\n", i, strerror(errno)); @@ -696,6 +698,8 @@ static int kvm_get_fp(CPUState *cs) for (i = 0; i < 32; i++) { uint64_t vsr[2]; + uint64_t *fpr = cpu_fpr_ptr(&cpu->env, i); + uint64_t *vsrl = cpu_vsrl_ptr(&cpu->env, i); reg.addr = (uintptr_t) &vsr; reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i); @@ -707,14 +711,14 @@ static int kvm_get_fp(CPUState *cs) return ret; } else { #ifdef HOST_WORDS_BIGENDIAN - env->fpr[i] = vsr[0]; + *fpr = vsr[0]; if (vsx) { - env->vsr[i] = vsr[1]; + *vsrl = vsr[1]; } #else - env->fpr[i] = vsr[1]; + *fpr = vsr[1]; if (vsx) { - env->vsr[i] = vsr[0]; + *vsrl = vsr[0]; } #endif } @@ -732,7 +736,7 @@ static int kvm_get_fp(CPUState *cs) for (i = 0; i < 32; i++) { reg.id = KVM_REG_PPC_VR(i); - reg.addr = (uintptr_t)&env->avr[i]; + reg.addr = (uintptr_t)cpu_avr_ptr(env, i); ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { DPRINTF("Unable to get VR%d from KVM: %s\n", diff --git a/target/ppc/machine.c b/target/ppc/machine.c index e7b3725273..eff30053b0 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -45,7 +45,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) uint64_t l; } u; u.l = qemu_get_be64(f); - env->fpr[i] = u.d; + *cpu_fpr_ptr(env, i) = u.d; } qemu_get_be32s(f, &fpscr); env->fpscr = fpscr; @@ -138,11 +138,73 @@ static const VMStateInfo vmstate_info_avr = { }; #define VMSTATE_AVR_ARRAY_V(_f, _s, _n, _v) \ - VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_avr, ppc_avr_t) + VMSTATE_SUB_ARRAY(_f, _s, 32, _n, _v, vmstate_info_avr, ppc_avr_t) #define VMSTATE_AVR_ARRAY(_f, _s, _n) \ VMSTATE_AVR_ARRAY_V(_f, _s, _n, 0) +static int get_fpr(QEMUFile *f, void *pv, size_t size, + const VMStateField *field) +{ + ppc_vsr_t *v = pv; + + v->u64[0] = qemu_get_be64(f); + + return 0; +} + +static int put_fpr(QEMUFile *f, void *pv, size_t size, + const VMStateField *field, QJSON *vmdesc) +{ + ppc_vsr_t *v = pv; + + qemu_put_be64(f, v->u64[0]); + return 0; +} + +static const VMStateInfo vmstate_info_fpr = { + .name = "fpr", + .get = get_fpr, + .put = put_fpr, +}; + +#define VMSTATE_FPR_ARRAY_V(_f, _s, _n, _v) \ + VMSTATE_SUB_ARRAY(_f, _s, 0, _n, _v, vmstate_info_fpr, ppc_vsr_t) + +#define VMSTATE_FPR_ARRAY(_f, _s, _n) \ + VMSTATE_FPR_ARRAY_V(_f, _s, _n, 0) + +static int get_vsr(QEMUFile *f, void *pv, size_t size, + const VMStateField *field) +{ + ppc_vsr_t *v = pv; + + v->u64[1] = qemu_get_be64(f); + + return 0; +} + +static int put_vsr(QEMUFile *f, void *pv, size_t size, + const VMStateField *field, QJSON *vmdesc) +{ + ppc_vsr_t *v = pv; + + qemu_put_be64(f, v->u64[1]); + return 0; +} + +static const VMStateInfo vmstate_info_vsr = { + .name = "vsr", + .get = get_vsr, + .put = put_vsr, +}; + +#define VMSTATE_VSR_ARRAY_V(_f, _s, _n, _v) \ + VMSTATE_SUB_ARRAY(_f, _s, 0, _n, _v, vmstate_info_vsr, ppc_vsr_t) + +#define VMSTATE_VSR_ARRAY(_f, _s, _n) \ + VMSTATE_VSR_ARRAY_V(_f, _s, _n, 0) + static bool cpu_pre_2_8_migration(void *opaque, int version_id) { PowerPCCPU *cpu = opaque; @@ -354,7 +416,7 @@ static const VMStateDescription vmstate_fpu = { .minimum_version_id = 1, .needed = fpu_needed, .fields = (VMStateField[]) { - VMSTATE_FLOAT64_ARRAY(env.fpr, PowerPCCPU, 32), + VMSTATE_FPR_ARRAY(env.vsr, PowerPCCPU, 32), VMSTATE_UINTTL(env.fpscr, PowerPCCPU), VMSTATE_END_OF_LIST() }, @@ -373,7 +435,7 @@ static const VMStateDescription vmstate_altivec = { .minimum_version_id = 1, .needed = altivec_needed, .fields = (VMStateField[]) { - VMSTATE_AVR_ARRAY(env.avr, PowerPCCPU, 32), + VMSTATE_AVR_ARRAY(env.vsr, PowerPCCPU, 32), VMSTATE_UINT32(env.vscr, PowerPCCPU), VMSTATE_END_OF_LIST() }, @@ -392,7 +454,7 @@ static const VMStateDescription vmstate_vsx = { .minimum_version_id = 1, .needed = vsx_needed, .fields = (VMStateField[]) { - VMSTATE_UINT64_ARRAY(env.vsr, PowerPCCPU, 32), + VMSTATE_VSR_ARRAY(env.vsr, PowerPCCPU, 32), VMSTATE_END_OF_LIST() }, }; diff --git a/target/ppc/monitor.c b/target/ppc/monitor.c index 14915119fc..04deec8030 100644 --- a/target/ppc/monitor.c +++ b/target/ppc/monitor.c @@ -123,8 +123,8 @@ int target_get_monitor_def(CPUState *cs, const char *name, uint64_t *pval) /* Floating point registers */ if ((qemu_tolower(name[0]) == 'f') && - ppc_cpu_get_reg_num(name + 1, ARRAY_SIZE(env->fpr), ®num)) { - *pval = env->fpr[regnum]; + ppc_cpu_get_reg_num(name + 1, 32, ®num)) { + *pval = *cpu_fpr_ptr(env, regnum); return 0; } diff --git a/target/ppc/translate.c b/target/ppc/translate.c index b18ded07b3..e169c43643 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6662,22 +6662,22 @@ GEN_TM_PRIV_NOOP(trechkpt); static inline void get_fpr(TCGv_i64 dst, int regno) { - tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, fpr[regno])); + tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, vsr[regno].u64[0])); } static inline void set_fpr(int regno, TCGv_i64 src) { - tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, fpr[regno])); + tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, vsr[regno].u64[0])); } static inline void get_avr64(TCGv_i64 dst, int regno, bool high) { #ifdef HOST_WORDS_BIGENDIAN tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, - avr[regno].u64[(high ? 0 : 1)])); + vsr[32 + regno].u64[(high ? 0 : 1)])); #else tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, - avr[regno].u64[(high ? 1 : 0)])); + vsr[32 + regno].u64[(high ? 1 : 0)])); #endif } @@ -6685,10 +6685,10 @@ static inline void set_avr64(int regno, TCGv_i64 src, bool high) { #ifdef HOST_WORDS_BIGENDIAN tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, - avr[regno].u64[(high ? 0 : 1)])); + vsr[32 + regno].u64[(high ? 0 : 1)])); #else tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, - avr[regno].u64[(high ? 1 : 0)])); + vsr[32 + regno].u64[(high ? 1 : 0)])); #endif } @@ -7440,7 +7440,7 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, if ((i & (RFPL - 1)) == 0) { cpu_fprintf(f, "FPR%02d", i); } - cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i])); + cpu_fprintf(f, " %016" PRIx64, *cpu_fpr_ptr(env, i)); if ((i & (RFPL - 1)) == (RFPL - 1)) { cpu_fprintf(f, "\n"); } diff --git a/target/ppc/translate/dfp-impl.inc.c b/target/ppc/translate/dfp-impl.inc.c index 634ef73b8a..6c556dc2e1 100644 --- a/target/ppc/translate/dfp-impl.inc.c +++ b/target/ppc/translate/dfp-impl.inc.c @@ -3,7 +3,7 @@ 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])); + tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, vsr[reg].u64[0])); return r; } diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c index 5e8327e9a3..f99d0284c2 100644 --- a/target/ppc/translate/vmx-impl.inc.c +++ b/target/ppc/translate/vmx-impl.inc.c @@ -10,10 +10,15 @@ 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])); + tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, vsr[32 + reg].u64[0])); return r; } +static inline long avr64_offset(int reg, bool high) +{ + return offsetof(CPUPPCState, vsr[32 + reg].u64[(high ? 0 : 1)]); +} + #define GEN_VR_LDX(name, opc2, opc3) \ static void glue(gen_, name)(DisasContext *ctx) \ { \ diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c index 7eaa36b4d5..ed4fdceacf 100644 --- a/target/ppc/translate/vsx-impl.inc.c +++ b/target/ppc/translate/vsx-impl.inc.c @@ -2,12 +2,12 @@ static inline void get_vsr(TCGv_i64 dst, int n) { - tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, vsr[n])); + tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, vsr[n].u64[1])); } static inline void set_vsr(int n, TCGv_i64 src) { - tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, vsr[n])); + tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, vsr[n].u64[1])); } static inline void get_cpu_vsrh(TCGv_i64 dst, int n) diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index 03f1d34a97..ade06cc773 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -9486,7 +9486,7 @@ static bool avr_need_swap(CPUPPCState *env) static int gdb_get_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n) { if (n < 32) { - stfq_p(mem_buf, env->fpr[n]); + stfq_p(mem_buf, *cpu_fpr_ptr(env, n)); ppc_maybe_bswap_register(env, mem_buf, 8); return 8; } @@ -9502,7 +9502,7 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n) { if (n < 32) { ppc_maybe_bswap_register(env, mem_buf, 8); - env->fpr[n] = ldfq_p(mem_buf); + *cpu_fpr_ptr(env, n) = ldfq_p(mem_buf); return 8; } if (n == 32) { @@ -9516,12 +9516,13 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n) static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n) { if (n < 32) { + ppc_avr_t *avr = cpu_avr_ptr(env, n); if (!avr_need_swap(env)) { - stq_p(mem_buf, env->avr[n].u64[0]); - stq_p(mem_buf+8, env->avr[n].u64[1]); + stq_p(mem_buf, avr->u64[0]); + stq_p(mem_buf + 8, avr->u64[1]); } else { - stq_p(mem_buf, env->avr[n].u64[1]); - stq_p(mem_buf+8, env->avr[n].u64[0]); + stq_p(mem_buf, avr->u64[1]); + stq_p(mem_buf + 8, avr->u64[0]); } ppc_maybe_bswap_register(env, mem_buf, 8); ppc_maybe_bswap_register(env, mem_buf + 8, 8); @@ -9543,14 +9544,15 @@ static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n) static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n) { if (n < 32) { + ppc_avr_t *avr = cpu_avr_ptr(env, n); ppc_maybe_bswap_register(env, mem_buf, 8); ppc_maybe_bswap_register(env, mem_buf + 8, 8); if (!avr_need_swap(env)) { - env->avr[n].u64[0] = ldq_p(mem_buf); - env->avr[n].u64[1] = ldq_p(mem_buf+8); + avr->u64[0] = ldq_p(mem_buf); + avr->u64[1] = ldq_p(mem_buf + 8); } else { - env->avr[n].u64[1] = ldq_p(mem_buf); - env->avr[n].u64[0] = ldq_p(mem_buf+8); + avr->u64[1] = ldq_p(mem_buf); + avr->u64[0] = ldq_p(mem_buf + 8); } return 16; } @@ -9623,7 +9625,7 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n) static int gdb_get_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n) { if (n < 32) { - stq_p(mem_buf, env->vsr[n]); + stq_p(mem_buf, *cpu_vsrl_ptr(env, n)); ppc_maybe_bswap_register(env, mem_buf, 8); return 8; } @@ -9634,7 +9636,7 @@ static int gdb_set_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n) { if (n < 32) { ppc_maybe_bswap_register(env, mem_buf, 8); - env->vsr[n] = ldq_p(mem_buf); + *cpu_vsrl_ptr(env, n) = ldq_p(mem_buf); return 8; } return 0; From 2dea57db6051afe3162192fe62c4694e17ec871f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 2 Jan 2019 09:14:23 +0000 Subject: [PATCH 13/29] target/ppc: replace AVR* macros with Vsr* macros Now that the VMX and VSR register sets have been combined, the same macros can be used to access both AVR and VSR field members. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target/ppc/int_helper.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 9d715be25c..598731d47a 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -391,13 +391,9 @@ target_ulong helper_602_mfrom(target_ulong arg) #if defined(HOST_WORDS_BIGENDIAN) #define HI_IDX 0 #define LO_IDX 1 -#define AVRB(i) u8[i] -#define AVRW(i) u32[i] #else #define HI_IDX 1 #define LO_IDX 0 -#define AVRB(i) u8[15-(i)] -#define AVRW(i) u32[3-(i)] #endif #if defined(HOST_WORDS_BIGENDIAN) @@ -3277,11 +3273,11 @@ void helper_vcipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) int i; VECTOR_FOR_INORDER_I(i, u32) { - result.AVRW(i) = b->AVRW(i) ^ - (AES_Te0[a->AVRB(AES_shifts[4*i + 0])] ^ - AES_Te1[a->AVRB(AES_shifts[4*i + 1])] ^ - AES_Te2[a->AVRB(AES_shifts[4*i + 2])] ^ - AES_Te3[a->AVRB(AES_shifts[4*i + 3])]); + result.VsrW(i) = b->VsrW(i) ^ + (AES_Te0[a->VsrB(AES_shifts[4 * i + 0])] ^ + AES_Te1[a->VsrB(AES_shifts[4 * i + 1])] ^ + AES_Te2[a->VsrB(AES_shifts[4 * i + 2])] ^ + AES_Te3[a->VsrB(AES_shifts[4 * i + 3])]); } *r = result; } @@ -3292,7 +3288,7 @@ void helper_vcipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) int i; VECTOR_FOR_INORDER_I(i, u8) { - result.AVRB(i) = b->AVRB(i) ^ (AES_sbox[a->AVRB(AES_shifts[i])]); + result.VsrB(i) = b->VsrB(i) ^ (AES_sbox[a->VsrB(AES_shifts[i])]); } *r = result; } @@ -3305,15 +3301,15 @@ void helper_vncipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) ppc_avr_t tmp; VECTOR_FOR_INORDER_I(i, u8) { - tmp.AVRB(i) = b->AVRB(i) ^ AES_isbox[a->AVRB(AES_ishifts[i])]; + tmp.VsrB(i) = b->VsrB(i) ^ AES_isbox[a->VsrB(AES_ishifts[i])]; } VECTOR_FOR_INORDER_I(i, u32) { - r->AVRW(i) = - AES_imc[tmp.AVRB(4*i + 0)][0] ^ - AES_imc[tmp.AVRB(4*i + 1)][1] ^ - AES_imc[tmp.AVRB(4*i + 2)][2] ^ - AES_imc[tmp.AVRB(4*i + 3)][3]; + r->VsrW(i) = + AES_imc[tmp.VsrB(4 * i + 0)][0] ^ + AES_imc[tmp.VsrB(4 * i + 1)][1] ^ + AES_imc[tmp.VsrB(4 * i + 2)][2] ^ + AES_imc[tmp.VsrB(4 * i + 3)][3]; } } @@ -3323,7 +3319,7 @@ void helper_vncipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) int i; VECTOR_FOR_INORDER_I(i, u8) { - result.AVRB(i) = b->AVRB(i) ^ (AES_isbox[a->AVRB(AES_ishifts[i])]); + result.VsrB(i) = b->VsrB(i) ^ (AES_isbox[a->VsrB(AES_ishifts[i])]); } *r = result; } From 2c6aba148c725996dac160151e0c58e72a07b799 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 2 Jan 2019 16:57:56 +0100 Subject: [PATCH 14/29] MAINTAINERS: Add some missing ppc-related files hw/gpio/mpc8xxx.c is only used by the e500 machine, so add it there. And the hw/input/adb* files are specific to the Mac machines, so they should be assigned to these categories. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- MAINTAINERS | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index fc0be06756..625e1c8c93 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -962,6 +962,7 @@ L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/ppc/e500.[hc] F: hw/ppc/e500plat.c +F: hw/gpio/mpc8xxx.c F: include/hw/ppc/ppc_e500.h F: include/hw/pci-host/ppce500.h F: pc-bios/u-boot.e500 @@ -973,7 +974,7 @@ S: Odd Fixes F: hw/ppc/mpc8544ds.c F: hw/ppc/mpc8544_guts.c -New World +New World (mac99) M: David Gibson L: qemu-ppc@nongnu.org S: Odd Fixes @@ -983,12 +984,14 @@ F: hw/pci-bridge/dec.[hc] F: hw/misc/macio/ F: hw/misc/mos6522.c F: hw/nvram/mac_nvram.c +F: hw/input/adb* F: include/hw/misc/macio/ F: include/hw/misc/mos6522.h F: include/hw/ppc/mac_dbdma.h F: include/hw/pci-host/uninorth.h +F: include/hw/input/adb* -Old World +Old World (g3beige) M: David Gibson L: qemu-ppc@nongnu.org S: Odd Fixes @@ -996,7 +999,9 @@ F: hw/ppc/mac_oldworld.c F: hw/pci-host/grackle.c F: hw/misc/macio/ F: hw/intc/heathrow_pic.c +F: hw/input/adb* F: include/hw/intc/heathrow_pic.h +F: include/hw/input/adb* PReP M: Hervé Poussineau From 52804c60f1bc31dbbc0fcf2d63268029fa93fe10 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 2 Jan 2019 10:22:43 +0000 Subject: [PATCH 15/29] MAINTAINERS: add qemu_vga.ndrv file entry for Mac machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VGA driver built from Ben's QemuMacDrivers repository is used exclusively by the Mac machines. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: David Gibson --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 625e1c8c93..87f90721b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -990,6 +990,7 @@ F: include/hw/misc/mos6522.h F: include/hw/ppc/mac_dbdma.h F: include/hw/pci-host/uninorth.h F: include/hw/input/adb* +F: pc-bios/qemu_vga.ndrv Old World (g3beige) M: David Gibson @@ -1002,6 +1003,7 @@ F: hw/intc/heathrow_pic.c F: hw/input/adb* F: include/hw/intc/heathrow_pic.h F: include/hw/input/adb* +F: pc-bios/qemu_vga.ndrv PReP M: Hervé Poussineau From 999c9caf2eee66103195e1ec7580b379929db9d2 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 21 Dec 2018 01:35:09 +0100 Subject: [PATCH 16/29] spapr: move spapr_create_phb() to core machine code This function is only used when creating the default PHB. Let's rename it and move it to the core machine code for clarity. Signed-off-by: Greg Kurz Reviewed-by: Alexey Kardashevskiy Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/ppc/spapr.c | 13 ++++++++++++- hw/ppc/spapr_pci.c | 11 ----------- include/hw/pci-host/spapr.h | 2 -- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 7e61f1e5ff..f621032d40 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2552,6 +2552,17 @@ static void spapr_init_cpus(sPAPRMachineState *spapr) } } +static PCIHostState *spapr_create_default_phb(void) +{ + DeviceState *dev; + + dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE); + qdev_prop_set_uint32(dev, "index", 0); + qdev_init_nofail(dev); + + return PCI_HOST_BRIDGE(dev); +} + /* pSeries LPAR / sPAPR hardware init */ static void spapr_machine_init(MachineState *machine) { @@ -2784,7 +2795,7 @@ static void spapr_machine_init(MachineState *machine) /* Set up PCI */ spapr_pci_rtas_init(); - phb = spapr_create_phb(spapr, 0); + phb = spapr_create_default_phb(); for (i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index bfb02ee96b..b74f2632ec 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1988,17 +1988,6 @@ static const TypeInfo spapr_phb_info = { } }; -PCIHostState *spapr_create_phb(sPAPRMachineState *spapr, int index) -{ - DeviceState *dev; - - dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE); - qdev_prop_set_uint32(dev, "index", index); - qdev_init_nofail(dev); - - return PCI_HOST_BRIDGE(dev); -} - typedef struct sPAPRFDT { void *fdt; int node_off; diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 7c66c3872f..a65cfef169 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -111,8 +111,6 @@ static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin) return spapr_qirq(spapr, phb->lsi_table[pin].irq); } -PCIHostState *spapr_create_phb(sPAPRMachineState *spapr, int index); - int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t xics_phandle, void *fdt, uint32_t nr_msis); From c13ee169115a4ad950e765e1bb5b9e6968aa8dfd Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Fri, 21 Dec 2018 01:35:30 +0100 Subject: [PATCH 17/29] pci: allow cleanup/unregistration of PCI root buses This adds cleanup counterparts to pci_register_root_bus(), pci_root_bus_new(), and pci_bus_irqs(). These cleanup routines are needed in the case of hotpluggable PCIHostBridge implementations. Currently we can rely on the object_unparent()'ing of the PCIHostState recursively unparenting and cleaning up it's child buses, but we need explicit calls to also: 1) remove the PCIHostState from pci_host_bridges global list. otherwise, we risk accessing freed memory when we access the list later 2) clean up memory allocated in pci_bus_irqs() Both are handled outside the context of any particular bus or host bridge's init/realize functions, making it difficult to avoid the need for explicit cleanup functions without remodeling how PCIHostBridges are created. So keep it simple and just add them for now. Cc: Michael S. Tsirkin Cc: Paolo Bonzini Signed-off-by: Michael Roth Reviewed-by: David Gibson Signed-off-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Signed-off-by: David Gibson --- hw/pci/pci.c | 33 +++++++++++++++++++++++++++++++++ include/hw/pci/pci.h | 3 +++ 2 files changed, 36 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index d831fa0a36..46d5010fac 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -333,6 +333,13 @@ static void pci_host_bus_register(DeviceState *host) QLIST_INSERT_HEAD(&pci_host_bridges, host_bridge, next); } +static void pci_host_bus_unregister(DeviceState *host) +{ + PCIHostState *host_bridge = PCI_HOST_BRIDGE(host); + + QLIST_REMOVE(host_bridge, next); +} + PCIBus *pci_device_root_bus(const PCIDevice *d) { PCIBus *bus = pci_get_bus(d); @@ -379,6 +386,11 @@ static void pci_root_bus_init(PCIBus *bus, DeviceState *parent, pci_host_bus_register(parent); } +static void pci_bus_uninit(PCIBus *bus) +{ + pci_host_bus_unregister(BUS(bus)->parent); +} + bool pci_bus_is_express(PCIBus *bus) { return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS); @@ -413,6 +425,12 @@ PCIBus *pci_root_bus_new(DeviceState *parent, const char *name, return bus; } +void pci_root_bus_cleanup(PCIBus *bus) +{ + pci_bus_uninit(bus); + object_unparent(OBJECT(bus)); +} + void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, int nirq) { @@ -423,6 +441,15 @@ void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0])); } +void pci_bus_irqs_cleanup(PCIBus *bus) +{ + bus->set_irq = NULL; + bus->map_irq = NULL; + bus->irq_opaque = NULL; + bus->nirq = 0; + g_free(bus->irq_count); +} + PCIBus *pci_register_root_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, @@ -439,6 +466,12 @@ PCIBus *pci_register_root_bus(DeviceState *parent, const char *name, return bus; } +void pci_unregister_root_bus(PCIBus *bus) +{ + pci_bus_irqs_cleanup(bus); + pci_root_bus_cleanup(bus); +} + int pci_bus_num(PCIBus *s) { return PCI_BUS_GET_CLASS(s)->bus_num(s); diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index eb12fa112e..d87f5f93e9 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -405,8 +405,10 @@ PCIBus *pci_root_bus_new(DeviceState *parent, const char *name, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, uint8_t devfn_min, const char *typename); +void pci_root_bus_cleanup(PCIBus *bus); void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, int nirq); +void pci_bus_irqs_cleanup(PCIBus *bus); int pci_bus_get_irq_level(PCIBus *bus, int irq_num); /* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */ int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin); @@ -417,6 +419,7 @@ PCIBus *pci_register_root_bus(DeviceState *parent, const char *name, MemoryRegion *address_space_io, uint8_t devfn_min, int nirq, const char *typename); +void pci_unregister_root_bus(PCIBus *bus); void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn); PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin); bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new); From 1da85c2ae691d5afae106feb419720838a693aac Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 21 Dec 2018 01:36:53 +0100 Subject: [PATCH 18/29] spapr_pci: Define SPAPR_MAX_PHBS in hw/pci-host/spapr.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PHB hotplug will bring more users for it. Let's define it along with the PHB defines from which it is derived for simplicity. While here fix a misleading comment about manual placement, which was abandoned with 30b3bc5aa9f4. Signed-off-by: Greg Kurz Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr.c | 2 -- include/hw/pci-host/spapr.h | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index f621032d40..75164ba4fc 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3840,8 +3840,6 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, * 1TiB 64-bit MMIO windows for each PHB. */ const uint64_t base_buid = 0x800000020000000ULL; -#define SPAPR_MAX_PHBS ((SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / \ - SPAPR_PCI_MEM64_WIN_SIZE - 1) int i; /* Sanity check natural alignments */ diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index a65cfef169..4eb3a2ce3e 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -94,11 +94,13 @@ struct sPAPRPHBState { ((1ULL << 32) - SPAPR_PCI_MEM_WIN_BUS_OFFSET) #define SPAPR_PCI_MEM64_WIN_SIZE 0x10000000000ULL /* 1 TiB */ -/* Without manual configuration, all PCI outbound windows will be - * within this range */ +/* All PCI outbound windows will be within this range */ #define SPAPR_PCI_BASE (1ULL << 45) /* 32 TiB */ #define SPAPR_PCI_LIMIT (1ULL << 46) /* 64 TiB */ +#define SPAPR_MAX_PHBS ((SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / \ + SPAPR_PCI_MEM64_WIN_SIZE - 1) + #define SPAPR_PCI_2_7_MMIO_WIN_SIZE 0xf80000000 #define SPAPR_PCI_IO_WIN_SIZE 0x10000 From a0c493ae67c8176bba0385aaab49d6129838b525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 2 Jan 2019 06:57:37 +0100 Subject: [PATCH 19/29] spapr/xive: simplify the sPAPR IRQ qirq method for XIVE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The qirq routines of the XiveSource and the sPAPRXive model are only used under the sPAPR IRQ backend. Simplify the overall call stack and gather all the code under spapr_qirq_xive(). It will ease future changes. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/intc/spapr_xive.c | 14 -------------- hw/ppc/spapr_irq.c | 12 +++++++++++- include/hw/ppc/spapr_xive.h | 1 - include/hw/ppc/xive.h | 6 ------ 4 files changed, 11 insertions(+), 22 deletions(-) diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 0e39c90cbd..eea28337e8 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -488,20 +488,6 @@ bool spapr_xive_irq_free(sPAPRXive *xive, uint32_t lisn) return true; } -qemu_irq spapr_xive_qirq(sPAPRXive *xive, uint32_t lisn) -{ - XiveSource *xsrc = &xive->source; - - if (lisn >= xive->nr_irqs) { - return NULL; - } - - /* The sPAPR machine/device should have claimed the IRQ before */ - assert(xive_eas_is_valid(&xive->eat[lisn])); - - return xive_source_qirq(xsrc, lisn); -} - /* * XIVE hcalls * diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 7b3b5afec2..be5fe531a8 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -284,7 +284,17 @@ static void spapr_irq_free_xive(sPAPRMachineState *spapr, int irq, int num) static qemu_irq spapr_qirq_xive(sPAPRMachineState *spapr, int irq) { - return spapr_xive_qirq(spapr->xive, irq); + sPAPRXive *xive = spapr->xive; + XiveSource *xsrc = &xive->source; + + if (irq >= xive->nr_irqs) { + return NULL; + } + + /* The sPAPR machine/device should have claimed the IRQ before */ + assert(xive_eas_is_valid(&xive->eat[irq])); + + return xsrc->qirqs[irq]; } static void spapr_irq_print_info_xive(sPAPRMachineState *spapr, diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index 728735dbcf..9ee524fdb2 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -40,7 +40,6 @@ typedef struct sPAPRXive { bool spapr_xive_irq_claim(sPAPRXive *xive, uint32_t lisn, bool lsi); bool spapr_xive_irq_free(sPAPRXive *xive, uint32_t lisn); void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon); -qemu_irq spapr_xive_qirq(sPAPRXive *xive, uint32_t lisn); typedef struct sPAPRMachineState sPAPRMachineState; diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 18cd114eb2..b05fe88b5b 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -278,12 +278,6 @@ uint8_t xive_source_esb_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq); void xive_source_pic_print_info(XiveSource *xsrc, uint32_t offset, Monitor *mon); -static inline qemu_irq xive_source_qirq(XiveSource *xsrc, uint32_t srcno) -{ - assert(srcno < xsrc->nr_irqs); - return xsrc->qirqs[srcno]; -} - static inline bool xive_source_irq_is_lsi(XiveSource *xsrc, uint32_t srcno) { assert(srcno < xsrc->nr_irqs); From 8fa1f4ef3828e71bfec1de2934c99e35c25709b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 2 Jan 2019 06:57:34 +0100 Subject: [PATCH 20/29] spapr: modify the prototype of the cpu_intc_create() method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Today, the interrupt presenter is linked to a CPU using the cpu_intc_create() method of the sPAPR IRQ backend. The resulting object is assigned to the PowerPCCPU 'intc' pointer whatever the interrupt mode, XICS or XIVE. To support the 'dual' interrupt mode, we will need to distinguish between the two presenter objects and for that, we plan to introduce a second interrupt presenter object pointer under the PowerPCCPU. The modifications below move the assignment of the presenter object under the cpu_intc_create() method to prepare ground for the future changes. Both sPAPR and PowerNV machines are impacted. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/pnv.c | 23 ++++++++++++++++------- hw/ppc/pnv_core.c | 2 +- hw/ppc/spapr_cpu_core.c | 2 +- hw/ppc/spapr_irq.c | 34 ++++++++++++++++++++++++++-------- include/hw/ppc/pnv.h | 2 +- include/hw/ppc/spapr_irq.h | 4 ++-- 6 files changed, 47 insertions(+), 20 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 346f5e7aed..8e83be54fc 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -668,11 +668,20 @@ static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id) return (chip->chip_id << 7) | (core_id << 3); } -static Object *pnv_chip_power8_intc_create(PnvChip *chip, Object *child, - Error **errp) +static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu, + Error **errp) { - return icp_create(child, TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()), - errp); + Error *local_err = NULL; + Object *obj; + + obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()), + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + cpu->intc = obj; } /* @@ -690,10 +699,10 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id) return (chip->chip_id << 8) | (core_id << 2); } -static Object *pnv_chip_power9_intc_create(PnvChip *chip, Object *child, - Error **errp) +static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu, + Error **errp) { - return NULL; + return; } /* Allowed core identifiers on a POWER8 Processor Chip : diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index ad1bcc7990..1202737748 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -114,7 +114,7 @@ static void pnv_realize_vcpu(PowerPCCPU *cpu, PnvChip *chip, Error **errp) return; } - cpu->intc = pcc->intc_create(chip, OBJECT(cpu), &local_err); + pcc->intc_create(chip, cpu, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 82666436e9..2739b2a4b8 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -232,7 +232,7 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr, qemu_register_reset(spapr_cpu_reset, cpu); spapr_cpu_reset(cpu); - cpu->intc = spapr->irq->cpu_intc_create(spapr, OBJECT(cpu), &local_err); + spapr->irq->cpu_intc_create(spapr, cpu, &local_err); if (local_err) { goto error_unregister; } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index be5fe531a8..eca2317cf3 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -190,10 +190,20 @@ static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon) ics_pic_print_info(spapr->ics, mon); } -static Object *spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr, - Object *cpu, Error **errp) +static void spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr, + PowerPCCPU *cpu, Error **errp) { - return icp_create(cpu, spapr->icp_type, XICS_FABRIC(spapr), errp); + Error *local_err = NULL; + Object *obj; + + obj = icp_create(OBJECT(cpu), spapr->icp_type, XICS_FABRIC(spapr), + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + cpu->intc = obj; } static int spapr_irq_post_load_xics(sPAPRMachineState *spapr, int version_id) @@ -311,17 +321,25 @@ static void spapr_irq_print_info_xive(sPAPRMachineState *spapr, spapr_xive_pic_print_info(spapr->xive, mon); } -static Object *spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr, - Object *cpu, Error **errp) +static void spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr, + PowerPCCPU *cpu, Error **errp) { - Object *obj = xive_tctx_create(cpu, XIVE_ROUTER(spapr->xive), errp); + Error *local_err = NULL; + Object *obj; + + obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(spapr->xive), &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + cpu->intc = obj; /* * (TCG) Early setting the OS CAM line for hotplugged CPUs as they - * don't benificiate from the reset of the XIVE IRQ backend + * don't beneficiate from the reset of the XIVE IRQ backend */ spapr_xive_set_tctx_os_cam(XIVE_TCTX(obj)); - return obj; } static int spapr_irq_post_load_xive(sPAPRMachineState *spapr, int version_id) diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index 86d5f54e54..6b65397b7e 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -98,7 +98,7 @@ typedef struct PnvChipClass { DeviceRealize parent_realize; uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id); - Object *(*intc_create)(PnvChip *chip, Object *child, Error **errp); + void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp); ISABus *(*isa_create)(PnvChip *chip, Error **errp); } PnvChipClass; diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index b34d5a0038..d03d4d7ce6 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -42,8 +42,8 @@ typedef struct sPAPRIrq { void (*print_info)(sPAPRMachineState *spapr, Monitor *mon); void (*dt_populate)(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt, uint32_t phandle); - Object *(*cpu_intc_create)(sPAPRMachineState *spapr, Object *cpu, - Error **errp); + void (*cpu_intc_create)(sPAPRMachineState *spapr, PowerPCCPU *cpu, + Error **errp); int (*post_load)(sPAPRMachineState *spapr, int version_id); void (*reset)(sPAPRMachineState *spapr, Error **errp); } sPAPRIrq; From 129dbe69266a9d5a4c492924a1d4b61a04f4cd7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 2 Jan 2019 06:57:35 +0100 Subject: [PATCH 21/29] ppc/xive: introduce a XiveTCTX pointer under PowerPCCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit which will be used by the machine only when the XIVE interrupt mode is in use. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/intc/xive.c | 6 +++--- hw/ppc/spapr_cpu_core.c | 7 ++++++- hw/ppc/spapr_irq.c | 8 ++++---- target/ppc/cpu.h | 2 ++ 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/hw/intc/xive.c b/hw/intc/xive.c index ea33494338..410c53278a 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -321,7 +321,7 @@ static void xive_tm_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PowerPCCPU *cpu = POWERPC_CPU(current_cpu); - XiveTCTX *tctx = XIVE_TCTX(cpu->intc); + XiveTCTX *tctx = cpu->tctx; const XiveTmOp *xto; /* @@ -360,7 +360,7 @@ static void xive_tm_write(void *opaque, hwaddr offset, static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size) { PowerPCCPU *cpu = POWERPC_CPU(current_cpu); - XiveTCTX *tctx = XIVE_TCTX(cpu->intc); + XiveTCTX *tctx = cpu->tctx; const XiveTmOp *xto; /* @@ -1186,7 +1186,7 @@ static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format, CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); - XiveTCTX *tctx = XIVE_TCTX(cpu->intc); + XiveTCTX *tctx = cpu->tctx; int ring; /* diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 2739b2a4b8..1473ef8533 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -194,7 +194,12 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc) vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data); } qemu_unregister_reset(spapr_cpu_reset, cpu); - object_unparent(cpu->intc); + if (cpu->intc) { + object_unparent(cpu->intc); + } + if (cpu->tctx) { + object_unparent(OBJECT(cpu->tctx)); + } cpu_remove_sync(CPU(cpu)); object_unparent(OBJECT(cpu)); } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index eca2317cf3..598b91a808 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -315,7 +315,7 @@ static void spapr_irq_print_info_xive(sPAPRMachineState *spapr, CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); - xive_tctx_pic_print_info(XIVE_TCTX(cpu->intc), mon); + xive_tctx_pic_print_info(cpu->tctx, mon); } spapr_xive_pic_print_info(spapr->xive, mon); @@ -333,13 +333,13 @@ static void spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr, return; } - cpu->intc = obj; + cpu->tctx = XIVE_TCTX(obj); /* * (TCG) Early setting the OS CAM line for hotplugged CPUs as they * don't beneficiate from the reset of the XIVE IRQ backend */ - spapr_xive_set_tctx_os_cam(XIVE_TCTX(obj)); + spapr_xive_set_tctx_os_cam(cpu->tctx); } static int spapr_irq_post_load_xive(sPAPRMachineState *spapr, int version_id) @@ -355,7 +355,7 @@ static void spapr_irq_reset_xive(sPAPRMachineState *spapr, Error **errp) PowerPCCPU *cpu = POWERPC_CPU(cs); /* (TCG) Set the OS CAM line of the thread interrupt context. */ - spapr_xive_set_tctx_os_cam(XIVE_TCTX(cpu->intc)); + spapr_xive_set_tctx_os_cam(cpu->tctx); } } diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 91951d7730..64e94fd83c 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1177,6 +1177,7 @@ do { \ typedef struct PPCVirtualHypervisor PPCVirtualHypervisor; typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass; +typedef struct XiveTCTX XiveTCTX; /** * PowerPCCPU: @@ -1196,6 +1197,7 @@ struct PowerPCCPU { uint32_t compat_pvr; PPCVirtualHypervisor *vhyp; Object *intc; + XiveTCTX *tctx; void *machine_data; int32_t node_id; /* NUMA node this CPU belongs to */ PPCHash64Options *hash64_opts; From 3ff73aa24125f18b3d1b24423213cc7d63a11f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 2 Jan 2019 06:57:36 +0100 Subject: [PATCH 22/29] ppc: replace the 'Object *intc' by a 'ICPState *icp' pointer under the CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the 'intc' pointer is only used by the XICS interrupt mode, let's make things clear and use a XICS type and name. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/intc/xics_spapr.c | 10 +++++----- hw/ppc/pnv.c | 6 +++--- hw/ppc/pnv_core.c | 2 +- hw/ppc/spapr.c | 2 +- hw/ppc/spapr_cpu_core.c | 4 ++-- hw/ppc/spapr_irq.c | 6 +++--- target/ppc/cpu.h | 3 ++- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index f67d3c80bf..9c1a90d709 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -44,7 +44,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr, { target_ulong cppr = args[0]; - icp_set_cppr(ICP(cpu->intc), cppr); + icp_set_cppr(cpu->icp, cppr); return H_SUCCESS; } @@ -65,7 +65,7 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr, static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { - uint32_t xirr = icp_accept(ICP(cpu->intc)); + uint32_t xirr = icp_accept(cpu->icp); args[0] = xirr; return H_SUCCESS; @@ -74,7 +74,7 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr, static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { - uint32_t xirr = icp_accept(ICP(cpu->intc)); + uint32_t xirr = icp_accept(cpu->icp); args[0] = xirr; args[1] = cpu_get_host_ticks(); @@ -86,7 +86,7 @@ static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr, { target_ulong xirr = args[0]; - icp_eoi(ICP(cpu->intc), xirr); + icp_eoi(cpu->icp, xirr); return H_SUCCESS; } @@ -94,7 +94,7 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { uint32_t mfrr; - uint32_t xirr = icp_ipoll(ICP(cpu->intc), &mfrr); + uint32_t xirr = icp_ipoll(cpu->icp, &mfrr); args[0] = xirr; args[1] = mfrr; diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 8e83be54fc..d84acef55b 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -681,7 +681,7 @@ static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu, return; } - cpu->intc = obj; + cpu->icp = ICP(obj); } /* @@ -1099,7 +1099,7 @@ static ICPState *pnv_icp_get(XICSFabric *xi, int pir) { PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir); - return cpu ? ICP(cpu->intc) : NULL; + return cpu ? cpu->icp : NULL; } static void pnv_pic_print_info(InterruptStatsProvider *obj, @@ -1112,7 +1112,7 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj, CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); - icp_pic_print_info(ICP(cpu->intc), mon); + icp_pic_print_info(cpu->icp, mon); } for (i = 0; i < pnv->num_chips; i++) { diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 1202737748..b98f277f1e 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -190,7 +190,7 @@ err: static void pnv_unrealize_vcpu(PowerPCCPU *cpu) { qemu_unregister_reset(pnv_cpu_reset, cpu); - object_unparent(cpu->intc); + object_unparent(OBJECT(cpu->icp)); cpu_remove_sync(CPU(cpu)); object_unparent(OBJECT(cpu)); } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 75164ba4fc..8576c1c6f7 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3887,7 +3887,7 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id) { PowerPCCPU *cpu = spapr_find_cpu(vcpu_id); - return cpu ? ICP(cpu->intc) : NULL; + return cpu ? cpu->icp : NULL; } static void spapr_pic_print_info(InterruptStatsProvider *obj, diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 1473ef8533..0405306d1e 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -194,8 +194,8 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc) vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data); } qemu_unregister_reset(spapr_cpu_reset, cpu); - if (cpu->intc) { - object_unparent(cpu->intc); + if (cpu->icp) { + object_unparent(OBJECT(cpu->icp)); } if (cpu->tctx) { object_unparent(OBJECT(cpu->tctx)); diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 598b91a808..b875065ef8 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -184,7 +184,7 @@ static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon) CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); - icp_pic_print_info(ICP(cpu->intc), mon); + icp_pic_print_info(cpu->icp, mon); } ics_pic_print_info(spapr->ics, mon); @@ -203,7 +203,7 @@ static void spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr, return; } - cpu->intc = obj; + cpu->icp = ICP(obj); } static int spapr_irq_post_load_xics(sPAPRMachineState *spapr, int version_id) @@ -212,7 +212,7 @@ static int spapr_irq_post_load_xics(sPAPRMachineState *spapr, int version_id) CPUState *cs; CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); - icp_resend(ICP(cpu->intc)); + icp_resend(cpu->icp); } } return 0; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 64e94fd83c..486abaf99b 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1178,6 +1178,7 @@ do { \ typedef struct PPCVirtualHypervisor PPCVirtualHypervisor; typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass; typedef struct XiveTCTX XiveTCTX; +typedef struct ICPState ICPState; /** * PowerPCCPU: @@ -1196,7 +1197,7 @@ struct PowerPCCPU { int vcpu_id; uint32_t compat_pvr; PPCVirtualHypervisor *vhyp; - Object *intc; + ICPState *icp; XiveTCTX *tctx; void *machine_data; int32_t node_id; /* NUMA node this CPU belongs to */ From e502202c9b6334343fe0004b7965d92e85ea1891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 4 Jan 2019 14:30:50 +0100 Subject: [PATCH 23/29] spapr: return from post_load method when RTC import fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error value can be squashed by the section handling radix migration. Simply bail out if an error occurs when the RTC offset is imported. This fixes the Coverity issue CID 1398591. Fixes: d39c90f5f3ae ("spapr: Fix migration of Radix guests") Signed-off-by: Cédric Le Goater Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8576c1c6f7..59faeccf4b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1747,12 +1747,17 @@ static int spapr_post_load(void *opaque, int version_id) return err; } - /* In earlier versions, there was no separate qdev for the PAPR + /* + * In earlier versions, there was no separate qdev for the PAPR * RTC, so the RTC offset was stored directly in sPAPREnvironment. * So when migrating from those versions, poke the incoming offset - * value into the RTC device */ + * value into the RTC device + */ if (version_id < 3) { err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset); + if (err) { + return err; + } } if (kvm_enabled() && spapr->patb_entry) { From 734d9c890588cf9d1c8f8e4538f98dec59df52e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 2 Jan 2019 06:57:38 +0100 Subject: [PATCH 24/29] ppc: export the XICS and XIVE set_irq handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support the 'dual' interrupt mode, XICS and XIVE, we plan to move the qemu_irq array of each interrupt controller under the machine and do the allocation under the sPAPR IRQ init method. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/intc/xics.c | 2 +- hw/intc/xics_kvm.c | 2 +- hw/intc/xive.c | 2 +- include/hw/ppc/xics.h | 2 ++ include/hw/ppc/xive.h | 2 ++ 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 406efee064..0d65549e3d 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -461,7 +461,7 @@ static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val) ics_simple_resend_lsi(ics, srcno); } -static void ics_simple_set_irq(void *opaque, int srcno, int val) +void ics_simple_set_irq(void *opaque, int srcno, int val) { ICSState *ics = (ICSState *)opaque; diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index e8fa9a53ae..c469c85d53 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -298,7 +298,7 @@ static int ics_set_kvm_state(ICSState *ics, int version_id) return 0; } -static void ics_kvm_set_irq(void *opaque, int srcno, int val) +void ics_kvm_set_irq(void *opaque, int srcno, int val) { ICSState *ics = opaque; struct kvm_irq_level args; diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 410c53278a..c759960895 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -845,7 +845,7 @@ static const MemoryRegionOps xive_source_esb_ops = { }, }; -static void xive_source_set_irq(void *opaque, int srcno, int val) +void xive_source_set_irq(void *opaque, int srcno, int val) { XiveSource *xsrc = XIVE_SOURCE(opaque); bool notify = false; diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 14afda198c..686db51149 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -192,6 +192,8 @@ void icp_eoi(ICPState *icp, uint32_t xirr); void ics_simple_write_xive(ICSState *ics, int nr, int server, uint8_t priority, uint8_t saved_priority); +void ics_simple_set_irq(void *opaque, int srcno, int val); +void ics_kvm_set_irq(void *opaque, int srcno, int val); void ics_set_irq_type(ICSState *ics, int srcno, bool lsi); void icp_pic_print_info(ICPState *icp, Monitor *mon); diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index b05fe88b5b..c279dc73b9 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -293,6 +293,8 @@ static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno, } } +void xive_source_set_irq(void *opaque, int srcno, int val); + /* * XIVE Router */ From f8df900316666f55dd82b1576e57f7650db682a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 2 Jan 2019 06:57:39 +0100 Subject: [PATCH 25/29] pnv/psi: move the ICSState qemu_irq array under the PSI device model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Future changes of the ICSState object will remove the qemu_irq array from under the interrupt controller model. Prepare ground for the PSI interrupt sources and introduce a new one directly under the PSI device model. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/pnv_psi.c | 7 ++++--- include/hw/ppc/pnv_psi.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 5b969127c3..8ced095063 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -207,7 +207,6 @@ static const uint64_t stat_bits[] = { void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state) { - ICSState *ics = &psi->ics; uint32_t xivr_reg; uint32_t stat_reg; uint32_t src; @@ -227,14 +226,14 @@ void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state) /* TODO: optimization, check mask here. That means * re-evaluating when unmasking */ - qemu_irq_raise(ics->qirqs[src]); + qemu_irq_raise(psi->qirqs[src]); } else { psi->regs[stat_reg] &= ~stat_bits[irq]; /* FSP and PSI are muxed so don't lower if either is still set */ if (stat_reg != PSIHB_XSCOM_CR || !(psi->regs[stat_reg] & (PSIHB_CR_PSI_IRQ | PSIHB_CR_FSP_IRQ))) { - qemu_irq_lower(ics->qirqs[src]); + qemu_irq_lower(psi->qirqs[src]); } else { state = true; } @@ -491,6 +490,8 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp) ics_set_irq_type(ics, i, true); } + psi->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs); + /* XSCOM region for PSI registers */ pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_xscom_ops, psi, "xscom-psi", PNV_XSCOM_PSIHB_SIZE); diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h index f6af5eae1f..64ac73512e 100644 --- a/include/hw/ppc/pnv_psi.h +++ b/include/hw/ppc/pnv_psi.h @@ -40,6 +40,7 @@ typedef struct PnvPsi { /* Interrupt generation */ ICSState ics; + qemu_irq *qirqs; /* Registers */ uint64_t regs[PSIHB_XSCOM_MAX]; From 872ff3dea3be974405709c4a96fccea65884835a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 2 Jan 2019 06:57:40 +0100 Subject: [PATCH 26/29] spapr: move the qemu_irq array under the machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The qemu_irq array is now allocated at the machine level using a sPAPR IRQ set_irq handler depending on the chosen interrupt mode. The use of this handler is slightly inefficient today but it will become necessary when the 'dual' interrupt mode is introduced. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/intc/xics.c | 2 -- hw/intc/xics_kvm.c | 1 - hw/intc/xive.c | 3 --- hw/ppc/spapr_irq.c | 30 +++++++++++++++++++++++++++--- include/hw/ppc/spapr.h | 1 + include/hw/ppc/spapr_irq.h | 1 + include/hw/ppc/xics.h | 1 - include/hw/ppc/xive.h | 1 - 8 files changed, 29 insertions(+), 11 deletions(-) diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 0d65549e3d..16e8ffa2aa 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -571,8 +571,6 @@ static void ics_simple_realize(DeviceState *dev, Error **errp) return; } - ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs); - qemu_register_reset(ics_simple_reset_handler, ics); } diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index c469c85d53..ac94594b19 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -344,7 +344,6 @@ static void ics_kvm_realize(DeviceState *dev, Error **errp) error_propagate(errp, local_err); return; } - ics->qirqs = qemu_allocate_irqs(ics_kvm_set_irq, ics, ics->nr_irqs); qemu_register_reset(ics_kvm_reset_handler, ics); } diff --git a/hw/intc/xive.c b/hw/intc/xive.c index c759960895..a3cb0cf0e3 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -932,9 +932,6 @@ static void xive_source_realize(DeviceState *dev, Error **errp) &xive_source_esb_ops, xsrc, "xive.esb", (1ull << xsrc->esb_shift) * xsrc->nr_irqs); - xsrc->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, - xsrc->nr_irqs); - qemu_register_reset(xive_source_reset, dev); } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index b875065ef8..d23914887a 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -171,7 +171,7 @@ static qemu_irq spapr_qirq_xics(sPAPRMachineState *spapr, int irq) uint32_t srcno = irq - ics->offset; if (ics_valid_irq(ics, irq)) { - return ics->qirqs[srcno]; + return spapr->qirqs[srcno]; } return NULL; @@ -218,6 +218,18 @@ static int spapr_irq_post_load_xics(sPAPRMachineState *spapr, int version_id) return 0; } +static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val) +{ + sPAPRMachineState *spapr = opaque; + MachineState *machine = MACHINE(opaque); + + if (kvm_enabled() && machine_kernel_irqchip_allowed(machine)) { + ics_kvm_set_irq(spapr->ics, srcno, val); + } else { + ics_simple_set_irq(spapr->ics, srcno, val); + } +} + #define SPAPR_IRQ_XICS_NR_IRQS 0x1000 #define SPAPR_IRQ_XICS_NR_MSIS \ (XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI) @@ -235,6 +247,7 @@ sPAPRIrq spapr_irq_xics = { .dt_populate = spapr_dt_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics, .post_load = spapr_irq_post_load_xics, + .set_irq = spapr_irq_set_irq_xics, }; /* @@ -295,7 +308,6 @@ static void spapr_irq_free_xive(sPAPRMachineState *spapr, int irq, int num) static qemu_irq spapr_qirq_xive(sPAPRMachineState *spapr, int irq) { sPAPRXive *xive = spapr->xive; - XiveSource *xsrc = &xive->source; if (irq >= xive->nr_irqs) { return NULL; @@ -304,7 +316,7 @@ static qemu_irq spapr_qirq_xive(sPAPRMachineState *spapr, int irq) /* The sPAPR machine/device should have claimed the IRQ before */ assert(xive_eas_is_valid(&xive->eat[irq])); - return xsrc->qirqs[irq]; + return spapr->qirqs[irq]; } static void spapr_irq_print_info_xive(sPAPRMachineState *spapr, @@ -359,6 +371,13 @@ static void spapr_irq_reset_xive(sPAPRMachineState *spapr, Error **errp) } } +static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val) +{ + sPAPRMachineState *spapr = opaque; + + xive_source_set_irq(&spapr->xive->source, srcno, val); +} + /* * XIVE uses the full IRQ number space. Set it to 8K to be compatible * with XICS. @@ -381,6 +400,7 @@ sPAPRIrq spapr_irq_xive = { .cpu_intc_create = spapr_irq_cpu_intc_create_xive, .post_load = spapr_irq_post_load_xive, .reset = spapr_irq_reset_xive, + .set_irq = spapr_irq_set_irq_xive, }; /* @@ -394,6 +414,9 @@ void spapr_irq_init(sPAPRMachineState *spapr, Error **errp) } spapr->irq->init(spapr, errp); + + spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, + spapr->irq->nr_irqs); } int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp) @@ -493,4 +516,5 @@ sPAPRIrq spapr_irq_xics_legacy = { .dt_populate = spapr_dt_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics, .post_load = spapr_irq_post_load_xics, + .set_irq = spapr_irq_set_irq_xics, }; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index fd24e91bd8..9e01a5a12e 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -182,6 +182,7 @@ struct sPAPRMachineState { unsigned long *irq_map; sPAPRXive *xive; sPAPRIrq *irq; + qemu_irq *qirqs; bool cmd_line_caps[SPAPR_CAP_NUM]; sPAPRCapabilities def, eff, mig; diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index d03d4d7ce6..283bb5002c 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -46,6 +46,7 @@ typedef struct sPAPRIrq { Error **errp); int (*post_load)(sPAPRMachineState *spapr, int version_id); void (*reset)(sPAPRMachineState *spapr, Error **errp); + void (*set_irq)(void *opaque, int srcno, int val); } sPAPRIrq; extern sPAPRIrq spapr_irq_xics; diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 686db51149..7668c381a8 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -131,7 +131,6 @@ struct ICSState { /*< public >*/ uint32_t nr_irqs; uint32_t offset; - qemu_irq *qirqs; ICSIRQState *irqs; XICSFabric *xics; }; diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index c279dc73b9..ec23253ba4 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -184,7 +184,6 @@ typedef struct XiveSource { /* IRQs */ uint32_t nr_irqs; - qemu_irq *qirqs; unsigned long *lsi_map; /* PQ bits and LSI assertion bit */ From 72c1e5a66affc2ae69342a4081361f69e1f686b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 2 Jan 2019 06:57:41 +0100 Subject: [PATCH 27/29] ppc/xics: allow ICSState to have an offset 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 15ed653fa49a ("ppc/xics: An ICS with offset 0 is assumed to be uninitialized") introduced an extra check on the ICS offset which is not strictly necessary. Revert the change to be able to map the XICS IRQ number space on the XIVE IRQ number space. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- include/hw/ppc/xics.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 7668c381a8..07508cbd21 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -139,8 +139,7 @@ struct ICSState { static inline bool ics_valid_irq(ICSState *ics, uint32_t nr) { - return (ics->offset != 0) && (nr >= ics->offset) - && (nr < (ics->offset + ics->nr_irqs)); + return (nr >= ics->offset) && (nr < (ics->offset + ics->nr_irqs)); } struct ICSIRQState { From 13db0cd9b853225e0061c95e922af8fd044473b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 2 Jan 2019 06:57:42 +0100 Subject: [PATCH 28/29] spapr: introduce a new sPAPR IRQ backend supporting XIVE and XICS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'dual' sPAPR IRQ backend supports both interrupt mode, XIVE exploitation mode and the legacy compatibility mode (XICS). both modes are not supported at the same time. The machine starts with the legacy mode and a new interrupt mode can then be negotiated by the CAS process. In this case, the new mode is activated after a reset to take into account the required changes in the machine. These impact the device tree layout, the interrupt presenter object and the exposed MMIO regions in the case of XIVE. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr.c | 10 ++- hw/ppc/spapr_hcall.c | 11 +++ hw/ppc/spapr_irq.c | 179 +++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr_irq.h | 1 + 4 files changed, 198 insertions(+), 3 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 59faeccf4b..83081defde 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2686,11 +2686,11 @@ static void spapr_machine_init(MachineState *machine) spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2); /* advertise XIVE on POWER9 machines */ - if (spapr->irq->ov5 & SPAPR_OV5_XIVE_EXPLOIT) { + if (spapr->irq->ov5 & (SPAPR_OV5_XIVE_EXPLOIT | SPAPR_OV5_XIVE_BOTH)) { if (ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0, spapr->max_compat_pvr)) { spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT); - } else { + } else if (spapr->irq->ov5 & SPAPR_OV5_XIVE_EXPLOIT) { error_report("XIVE-only machines require a POWER9 CPU"); exit(1); } @@ -3116,6 +3116,8 @@ static char *spapr_get_ic_mode(Object *obj, Error **errp) return g_strdup("xics"); } else if (spapr->irq == &spapr_irq_xive) { return g_strdup("xive"); + } else if (spapr->irq == &spapr_irq_dual) { + return g_strdup("dual"); } g_assert_not_reached(); } @@ -3129,6 +3131,8 @@ static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp) spapr->irq = &spapr_irq_xics; } else if (strcmp(value, "xive") == 0) { spapr->irq = &spapr_irq_xive; + } else if (strcmp(value, "dual") == 0) { + spapr->irq = &spapr_irq_dual; } else { error_setg(errp, "Bad value for \"ic-mode\" property"); } @@ -3177,7 +3181,7 @@ static void spapr_instance_init(Object *obj) object_property_add_str(obj, "ic-mode", spapr_get_ic_mode, spapr_set_ic_mode, NULL); object_property_set_description(obj, "ic-mode", - "Specifies the interrupt controller mode (xics, xive)", + "Specifies the interrupt controller mode (xics, xive, dual)", NULL); } diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 1ae3e6ff5e..17bcaa3822 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1654,6 +1654,17 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, (spapr_h_cas_compose_response(spapr, args[1], args[2], ov5_updates) != 0); } + + /* + * Generate a machine reset when we have an update of the + * interrupt mode. Only required when the machine supports both + * modes. + */ + if (!spapr->cas_reboot) { + spapr->cas_reboot = spapr_ovec_test(ov5_updates, OV5_XIVE_EXPLOIT) + && spapr->irq->ov5 & SPAPR_OV5_XIVE_BOTH; + } + spapr_ovec_cleanup(ov5_updates); if (spapr->cas_reboot) { diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index d23914887a..d110b8cdee 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -230,6 +230,11 @@ static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val) } } +static void spapr_irq_reset_xics(sPAPRMachineState *spapr, Error **errp) +{ + /* TODO: create the KVM XICS device */ +} + #define SPAPR_IRQ_XICS_NR_IRQS 0x1000 #define SPAPR_IRQ_XICS_NR_MSIS \ (XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI) @@ -247,6 +252,7 @@ sPAPRIrq spapr_irq_xics = { .dt_populate = spapr_dt_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics, .post_load = spapr_irq_post_load_xics, + .reset = spapr_irq_reset_xics, .set_irq = spapr_irq_set_irq_xics, }; @@ -403,6 +409,179 @@ sPAPRIrq spapr_irq_xive = { .set_irq = spapr_irq_set_irq_xive, }; +/* + * Dual XIVE and XICS IRQ backend. + * + * Both interrupt mode, XIVE and XICS, objects are created but the + * machine starts in legacy interrupt mode (XICS). It can be changed + * by the CAS negotiation process and, in that case, the new mode is + * activated after an extra machine reset. + */ + +/* + * Returns the sPAPR IRQ backend negotiated by CAS. XICS is the + * default. + */ +static sPAPRIrq *spapr_irq_current(sPAPRMachineState *spapr) +{ + return spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT) ? + &spapr_irq_xive : &spapr_irq_xics; +} + +static void spapr_irq_init_dual(sPAPRMachineState *spapr, Error **errp) +{ + MachineState *machine = MACHINE(spapr); + Error *local_err = NULL; + + if (kvm_enabled() && machine_kernel_irqchip_allowed(machine)) { + error_setg(errp, "No KVM support for the 'dual' machine"); + return; + } + + spapr_irq_xics.init(spapr, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + /* + * Align the XICS and the XIVE IRQ number space under QEMU. + * + * However, the XICS KVM device still considers that the IRQ + * numbers should start at XICS_IRQ_BASE (0x1000). Either we + * should introduce a KVM device ioctl to set the offset or ignore + * the lower 4K numbers when using the get/set ioctl of the XICS + * KVM device. The second option seems the least intrusive. + */ + spapr->ics->offset = 0; + + spapr_irq_xive.init(spapr, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } +} + +static int spapr_irq_claim_dual(sPAPRMachineState *spapr, int irq, bool lsi, + Error **errp) +{ + Error *local_err = NULL; + int ret; + + ret = spapr_irq_xics.claim(spapr, irq, lsi, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return ret; + } + + ret = spapr_irq_xive.claim(spapr, irq, lsi, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return ret; + } + + return ret; +} + +static void spapr_irq_free_dual(sPAPRMachineState *spapr, int irq, int num) +{ + spapr_irq_xics.free(spapr, irq, num); + spapr_irq_xive.free(spapr, irq, num); +} + +static qemu_irq spapr_qirq_dual(sPAPRMachineState *spapr, int irq) +{ + sPAPRXive *xive = spapr->xive; + ICSState *ics = spapr->ics; + + if (irq >= spapr->irq->nr_irqs) { + return NULL; + } + + /* + * The IRQ number should have been claimed under both interrupt + * controllers. + */ + assert(!ICS_IRQ_FREE(ics, irq - ics->offset)); + assert(xive_eas_is_valid(&xive->eat[irq])); + + return spapr->qirqs[irq]; +} + +static void spapr_irq_print_info_dual(sPAPRMachineState *spapr, Monitor *mon) +{ + spapr_irq_current(spapr)->print_info(spapr, mon); +} + +static void spapr_irq_dt_populate_dual(sPAPRMachineState *spapr, + uint32_t nr_servers, void *fdt, + uint32_t phandle) +{ + spapr_irq_current(spapr)->dt_populate(spapr, nr_servers, fdt, phandle); +} + +static void spapr_irq_cpu_intc_create_dual(sPAPRMachineState *spapr, + PowerPCCPU *cpu, Error **errp) +{ + Error *local_err = NULL; + + spapr_irq_xive.cpu_intc_create(spapr, cpu, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + spapr_irq_xics.cpu_intc_create(spapr, cpu, errp); +} + +static int spapr_irq_post_load_dual(sPAPRMachineState *spapr, int version_id) +{ + /* + * Force a reset of the XIVE backend after migration. The machine + * defaults to XICS at startup. + */ + if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + spapr_irq_xive.reset(spapr, &error_fatal); + } + + return spapr_irq_current(spapr)->post_load(spapr, version_id); +} + +static void spapr_irq_reset_dual(sPAPRMachineState *spapr, Error **errp) +{ + spapr_irq_current(spapr)->reset(spapr, errp); +} + +static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val) +{ + sPAPRMachineState *spapr = opaque; + + spapr_irq_current(spapr)->set_irq(spapr, srcno, val); +} + +/* + * Define values in sync with the XIVE and XICS backend + */ +#define SPAPR_IRQ_DUAL_NR_IRQS 0x2000 +#define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI) + +sPAPRIrq spapr_irq_dual = { + .nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS, + .nr_msis = SPAPR_IRQ_DUAL_NR_MSIS, + .ov5 = SPAPR_OV5_XIVE_BOTH, + + .init = spapr_irq_init_dual, + .claim = spapr_irq_claim_dual, + .free = spapr_irq_free_dual, + .qirq = spapr_qirq_dual, + .print_info = spapr_irq_print_info_dual, + .dt_populate = spapr_irq_dt_populate_dual, + .cpu_intc_create = spapr_irq_cpu_intc_create_dual, + .post_load = spapr_irq_post_load_dual, + .reset = spapr_irq_reset_dual, + .set_irq = spapr_irq_set_irq_dual +}; + /* * sPAPR IRQ frontend routines for devices */ diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index 283bb5002c..14b02c3aca 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -52,6 +52,7 @@ typedef struct sPAPRIrq { extern sPAPRIrq spapr_irq_xics; extern sPAPRIrq spapr_irq_xics_legacy; extern sPAPRIrq spapr_irq_xive; +extern sPAPRIrq spapr_irq_dual; void spapr_irq_init(sPAPRMachineState *spapr, Error **errp); int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp); From 3a8eb78e6c135422017888380db091793039b6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 2 Jan 2019 06:57:43 +0100 Subject: [PATCH 29/29] spapr: enable XIVE MMIOs at reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Depending on the interrupt mode of the machine, enable or disable the XIVE MMIOs. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/intc/spapr_xive.c | 9 +++++++++ hw/ppc/spapr_irq.c | 9 +++++++++ include/hw/ppc/spapr_xive.h | 1 + 3 files changed, 19 insertions(+) diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index eea28337e8..d391177ab8 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -179,6 +179,15 @@ static void spapr_xive_map_mmio(sPAPRXive *xive) sysbus_mmio_map(SYS_BUS_DEVICE(xive), 2, xive->tm_base); } +void spapr_xive_mmio_set_enabled(sPAPRXive *xive, bool enable) +{ + memory_region_set_enabled(&xive->source.esb_mmio, enable); + memory_region_set_enabled(&xive->tm_mmio, enable); + + /* Disable the END ESBs until a guest OS makes use of them */ + memory_region_set_enabled(&xive->end_source.esb_mmio, false); +} + /* * When a Virtual Processor is scheduled to run on a HW thread, the * hypervisor pushes its identifier in the OS CAM line. Emulate the diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index d110b8cdee..5fce72fe0f 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -375,6 +375,9 @@ static void spapr_irq_reset_xive(sPAPRMachineState *spapr, Error **errp) /* (TCG) Set the OS CAM line of the thread interrupt context. */ spapr_xive_set_tctx_os_cam(cpu->tctx); } + + /* Activate the XIVE MMIOs */ + spapr_xive_mmio_set_enabled(spapr->xive, true); } static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val) @@ -549,6 +552,12 @@ static int spapr_irq_post_load_dual(sPAPRMachineState *spapr, int version_id) static void spapr_irq_reset_dual(sPAPRMachineState *spapr, Error **errp) { + /* + * Deactivate the XIVE MMIOs. The XIVE backend will reenable them + * if selected. + */ + spapr_xive_mmio_set_enabled(spapr->xive, false); + spapr_irq_current(spapr)->reset(spapr, errp); } diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index 9ee524fdb2..7fdc250574 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -47,5 +47,6 @@ void spapr_xive_hcall_init(sPAPRMachineState *spapr); void spapr_dt_xive(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt, uint32_t phandle); void spapr_xive_set_tctx_os_cam(XiveTCTX *tctx); +void spapr_xive_mmio_set_enabled(sPAPRXive *xive, bool enable); #endif /* PPC_SPAPR_XIVE_H */