diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-06-03 10:00:35 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-06-03 10:00:35 +0100 |
commit | a97978bcc2d1f650c7d411428806e5b03082b8c7 (patch) | |
tree | 29f81b0392e3b87dfa81c5ef10849225307d60bc | |
parent | 8e6dad2028d01b7f9ec76cf3b83457fab57fa1eb (diff) | |
parent | eba3c766fe355a4e593c1ee6944770f80b68acad (diff) |
Merge remote-tracking branch 'remotes/dg-gitlab/tags/ppc-for-6.1-20210603' into staging
ppc patch queue 2021-06-03
Next batch of ppc target patches. Highlights are:
* A fix for a regression with single-step mode
* Start of moving ppc to use decodetree
* Implementation of some POWER10 64-bit prefixed instructions
* Several cleanups to softmmu code
* Continued progress towards allowing --disable-tcg
* Fix for the POWER PEF implementation
* Fix for LPCR handling of hotplugged CPUs
* Assorted other bugfixes and cleanups
This patchset does contain a couple of changes to code outside my
normal scope of maintainership, related to the removal of cpu_dump and
cpu_statistics hooks. ppc was the last target arch implementing these
at all, and they didn't really do anything there either. The patches
should have relevant acks.
# gpg: Signature made Thu 03 Jun 2021 09:20:59 BST
# gpg: using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full]
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full]
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full]
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown]
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dg-gitlab/tags/ppc-for-6.1-20210603: (42 commits)
target/ppc: fix single-step exception regression
target/ppc: Move cmp/cmpi/cmpl/cmpli to decodetree
target/ppc: Move addpcis to decodetree
target/ppc: Implement vcfuged instruction
target/ppc: Implement cfuged instruction
target/ppc: Implement setbc/setbcr/stnbc/setnbcr instructions
target/ppc: Implement prefixed integer store instructions
target/ppc: Move D/DS/X-form integer stores to decodetree
target/ppc: Implement prefixed integer load instructions
target/ppc: Move D/DS/X-form integer loads to decodetree
target/ppc: Implement PNOP
target/ppc: Move ADDI, ADDIS to decodetree, implement PADDI
target/ppc: Add infrastructure for prefixed insns
target/ppc: Move page crossing check to ppc_tr_translate_insn
target/ppc: Introduce macros to check isa extensions
target/ppc: powerpc_excp: Consolidade TLB miss code
target/ppc: powerpc_excp: Remove dump_syscall_vectored
target/ppc: powerpc_excp: Move lpes code to where it is used
target/ppc: overhauled and moved logic of storing fpscr
target/ppc: removed all mentions to PPC_DUMP_CPU
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
33 files changed, 1064 insertions, 1208 deletions
diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst index 5a462ac568..1d22195b1d 100644 --- a/docs/system/removed-features.rst +++ b/docs/system/removed-features.rst @@ -249,6 +249,11 @@ Use ``migrate-set-parameters`` and ``info migrate-parameters`` instead. Use ``migrate-set-parameters`` instead. +``info cpustats`` (removed in 6.1) +'''''''''''''''''''''''''''''''''' + +This command didn't produce any output already. Removed with no replacement. + Guest Emulator ISAs ------------------- diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index ab0c7aa5ee..b2347a6aea 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -500,19 +500,6 @@ SRST Show the current VM UUID. ERST - { - .name = "cpustats", - .args_type = "", - .params = "", - .help = "show CPU statistics", - .cmd = hmp_info_cpustats, - }, - -SRST - ``info cpustats`` - Show CPU statistics. -ERST - #if defined(CONFIG_SLIRP) { .name = "usernet", diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 9530e266ec..e2f5a64604 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -109,15 +109,6 @@ void cpu_dump_state(CPUState *cpu, FILE *f, int flags) } } -void cpu_dump_statistics(CPUState *cpu, int flags) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - if (cc->dump_statistics) { - cc->dump_statistics(cpu, flags); - } -} - void cpu_reset(CPUState *cpu) { device_cold_reset(DEVICE(cpu)); diff --git a/hw/ppc/pef.c b/hw/ppc/pef.c index 573be3ed79..cc44d5e339 100644 --- a/hw/ppc/pef.c +++ b/hw/ppc/pef.c @@ -41,7 +41,7 @@ struct PefGuest { ConfidentialGuestSupport parent_obj; }; -static int kvmppc_svm_init(Error **errp) +static int kvmppc_svm_init(ConfidentialGuestSupport *cgs, Error **errp) { #ifdef CONFIG_KVM static Error *pef_mig_blocker; @@ -65,6 +65,8 @@ static int kvmppc_svm_init(Error **errp) /* NB: This can fail if --only-migratable is used */ migrate_add_blocker(pef_mig_blocker, &error_fatal); + cgs->ready = true; + return 0; #else g_assert_not_reached(); @@ -102,7 +104,7 @@ int pef_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) return -1; } - return kvmppc_svm_init(errp); + return kvmppc_svm_init(cgs, errp); } int pef_kvm_reset(ConfidentialGuestSupport *cgs, Error **errp) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c23bcc4490..4dd90b75cc 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1005,7 +1005,7 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset) _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen")); if (reset) { - const char *boot_device = machine->boot_order; + const char *boot_device = spapr->boot_device; char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus); size_t cb = 0; char *bootlist = get_boot_devices_list(&cb); @@ -2376,8 +2376,10 @@ static SaveVMHandlers savevm_htab_handlers = { static void spapr_boot_set(void *opaque, const char *boot_device, Error **errp) { - MachineState *machine = MACHINE(opaque); - machine->boot_order = g_strdup(boot_device); + SpaprMachineState *spapr = SPAPR_MACHINE(opaque); + + g_free(spapr->boot_device); + spapr->boot_device = g_strdup(boot_device); } static void spapr_create_lmb_dr_connectors(SpaprMachineState *spapr) diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index 252204e25f..91de1052f2 100644 --- a/hw/ppc/spapr_nvdimm.c +++ b/hw/ppc/spapr_nvdimm.c @@ -35,6 +35,18 @@ /* SCM device is unable to persist memory contents */ #define PAPR_PMEM_UNARMED PPC_BIT(0) +/* + * The nvdimm size should be aligned to SCM block size. + * The SCM block size should be aligned to SPAPR_MEMORY_BLOCK_SIZE + * in order to have SCM regions not to overlap with dimm memory regions. + * The SCM devices can have variable block sizes. For now, fixing the + * block size to the minimum value. + */ +#define SPAPR_MINIMUM_SCM_BLOCK_SIZE SPAPR_MEMORY_BLOCK_SIZE + +/* Have an explicit check for alignment */ +QEMU_BUILD_BUG_ON(SPAPR_MINIMUM_SCM_BLOCK_SIZE % SPAPR_MEMORY_BLOCK_SIZE); + bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm, uint64_t size, Error **errp) { @@ -163,11 +175,11 @@ int spapr_pmem_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, void spapr_dt_persistent_memory(SpaprMachineState *spapr, void *fdt) { - int offset = fdt_subnode_offset(fdt, 0, "persistent-memory"); + int offset = fdt_subnode_offset(fdt, 0, "ibm,persistent-memory"); GSList *iter, *nvdimms = nvdimm_get_device_list(); if (offset < 0) { - offset = fdt_add_subnode(fdt, 0, "persistent-memory"); + offset = fdt_add_subnode(fdt, 0, "ibm,persistent-memory"); _FDT(offset); _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0x1))); _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0x0))); diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c index 7817cf72ee..f3b37df8ea 100644 --- a/hw/ppc/spapr_pci_vfio.c +++ b/hw/ppc/spapr_pci_vfio.c @@ -46,6 +46,16 @@ void spapr_phb_vfio_reset(DeviceState *qdev) spapr_phb_vfio_eeh_reenable(SPAPR_PCI_HOST_BRIDGE(qdev)); } +static void spapr_eeh_pci_find_device(PCIBus *bus, PCIDevice *pdev, + void *opaque) +{ + bool *found = opaque; + + if (object_dynamic_cast(OBJECT(pdev), "vfio-pci")) { + *found = true; + } +} + int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb, unsigned int addr, int option) { @@ -58,17 +68,33 @@ int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb, break; case RTAS_EEH_ENABLE: { PCIHostState *phb; - PCIDevice *pdev; + bool found = false; /* - * The EEH functionality is enabled on basis of PCI device, - * instead of PE. We need check the validity of the PCI - * device address. + * The EEH functionality is enabled per sphb level instead of + * per PCI device. We have already identified this specific sphb + * based on buid passed as argument to ibm,set-eeh-option rtas + * call. Now we just need to check the validity of the PCI + * pass-through devices (vfio-pci) under this sphb bus. + * We have already validated that all the devices under this sphb + * are from same iommu group (within same PE) before comming here. + * + * Prior to linux commit 98ba956f6a389 ("powerpc/pseries/eeh: + * Rework device EEH PE determination") kernel would call + * eeh-set-option for each device in the PE using the device's + * config_address as the argument rather than the PE address. + * Hence if we check validity of supplied config_addr whether + * it matches to this PHB will cause issues with older kernel + * versions v5.9 and older. If we return an error from + * eeh-set-option when the argument isn't a valid PE address + * then older kernels (v5.9 and older) will interpret that as + * EEH not being supported. */ phb = PCI_HOST_BRIDGE(sphb); - pdev = pci_find_device(phb->bus, - (addr >> 16) & 0xFF, (addr >> 8) & 0xFF); - if (!pdev || !object_dynamic_cast(OBJECT(pdev), "vfio-pci")) { + pci_for_each_device(phb->bus, (addr >> 16) & 0xFF, + spapr_eeh_pci_find_device, &found); + + if (!found) { return RTAS_OUT_PARAM_ERROR; } diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 03355b4c0a..b476382ae6 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -132,8 +132,8 @@ static void rtas_start_cpu(PowerPCCPU *callcpu, SpaprMachineState *spapr, target_ulong id, start, r3; PowerPCCPU *newcpu; CPUPPCState *env; - PowerPCCPUClass *pcc; target_ulong lpcr; + target_ulong caller_lpcr; if (nargs != 3 || nret != 1) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); @@ -152,7 +152,6 @@ static void rtas_start_cpu(PowerPCCPU *callcpu, SpaprMachineState *spapr, } env = &newcpu->env; - pcc = POWERPC_CPU_GET_CLASS(newcpu); if (!CPU(newcpu)->halted) { rtas_st(rets, 0, RTAS_OUT_HW_ERROR); @@ -164,11 +163,15 @@ static void rtas_start_cpu(PowerPCCPU *callcpu, SpaprMachineState *spapr, env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); hreg_compute_hflags(env); - /* Enable Power-saving mode Exit Cause exceptions for the new CPU */ + caller_lpcr = callcpu->env.spr[SPR_LPCR]; lpcr = env->spr[SPR_LPCR]; - if (!pcc->interrupts_big_endian(callcpu)) { - lpcr |= LPCR_ILE; - } + + /* Set ILE the same way */ + lpcr = (lpcr & ~LPCR_ILE) | (caller_lpcr & LPCR_ILE); + + /* Set AIL the same way */ + lpcr = (lpcr & ~LPCR_AIL) | (caller_lpcr & LPCR_AIL); + if (env->mmu_model == POWERPC_MMU_3_00) { /* * New cpus are expected to start in the same radix/hash mode diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 044f668a6e..6b3bd3a1d4 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -92,7 +92,6 @@ struct SysemuCPUOps; * @has_work: Callback for checking if there is work to do. * @memory_rw_debug: Callback for GDB memory access. * @dump_state: Callback for dumping state. - * @dump_statistics: Callback for dumping statistics. * @get_arch_id: Callback for getting architecture-dependent CPU ID. * @set_pc: Callback for setting the Program Counter register. This * should have the semantics used by the target architecture when @@ -134,7 +133,6 @@ struct CPUClass { int (*memory_rw_debug)(CPUState *cpu, vaddr addr, uint8_t *buf, int len, bool is_write); void (*dump_state)(CPUState *cpu, FILE *, int flags); - void (*dump_statistics)(CPUState *cpu, int flags); int64_t (*get_arch_id)(CPUState *cpu); void (*set_pc)(CPUState *cpu, vaddr value); int (*gdb_read_register)(CPUState *cpu, GByteArray *buf, int reg); @@ -534,16 +532,6 @@ enum CPUDumpFlags { */ void cpu_dump_state(CPUState *cpu, FILE *f, int flags); -/** - * cpu_dump_statistics: - * @cpu: The CPU whose state is to be dumped. - * @flags: Flags what to dump. - * - * Dump CPU statistics to the current monitor if we have one, else to - * stdout. - */ -void cpu_dump_statistics(CPUState *cpu, int flags); - #ifndef CONFIG_USER_ONLY /** * cpu_get_phys_page_attrs_debug: diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index bbf817af46..f05219f75e 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -223,6 +223,9 @@ struct SpaprMachineState { int fwnmi_machine_check_interlock; QemuCond fwnmi_machine_check_interlock_cond; + /* Set by -boot */ + char *boot_device; + /*< public >*/ char *kvm_type; char *host_model; diff --git a/include/hw/ppc/spapr_nvdimm.h b/include/hw/ppc/spapr_nvdimm.h index 73be250e2a..764f999f54 100644 --- a/include/hw/ppc/spapr_nvdimm.h +++ b/include/hw/ppc/spapr_nvdimm.h @@ -11,19 +11,9 @@ #define HW_SPAPR_NVDIMM_H #include "hw/mem/nvdimm.h" -#include "hw/ppc/spapr.h" -/* - * The nvdimm size should be aligned to SCM block size. - * The SCM block size should be aligned to SPAPR_MEMORY_BLOCK_SIZE - * inorder to have SCM regions not to overlap with dimm memory regions. - * The SCM devices can have variable block sizes. For now, fixing the - * block size to the minimum value. - */ -#define SPAPR_MINIMUM_SCM_BLOCK_SIZE SPAPR_MEMORY_BLOCK_SIZE - -/* Have an explicit check for alignment */ -QEMU_BUILD_BUG_ON(SPAPR_MINIMUM_SCM_BLOCK_SIZE % SPAPR_MEMORY_BLOCK_SIZE); +typedef struct SpaprDrc SpaprDrc; +typedef struct SpaprMachineState SpaprMachineState; int spapr_pmem_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, void *fdt, int *fdt_start_offset, Error **errp); diff --git a/monitor/misc.c b/monitor/misc.c index f3a393ea59..1539e18557 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -369,17 +369,6 @@ static void hmp_info_history(Monitor *mon, const QDict *qdict) } } -static void hmp_info_cpustats(Monitor *mon, const QDict *qdict) -{ - CPUState *cs = mon_get_cpu(mon); - - if (!cs) { - monitor_printf(mon, "No CPU available\n"); - return; - } - cpu_dump_statistics(cs, 0); -} - static void hmp_info_trace_events(Monitor *mon, const QDict *qdict) { const char *name = qdict_get_try_str(qdict, "name"); diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c index d957d1a687..19d67b5b07 100644 --- a/target/ppc/cpu.c +++ b/target/ppc/cpu.c @@ -24,6 +24,8 @@ #include "exec/log.h" #include "fpu/softfloat-helpers.h" #include "mmu-hash64.h" +#include "helper_regs.h" +#include "sysemu/tcg.h" target_ulong cpu_read_xer(CPUPPCState *env) { @@ -77,13 +79,13 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value) target_ulong htabsize = value & SDR_64_HTABSIZE; if (value & ~sdr_mask) { - error_report("Invalid bits 0x"TARGET_FMT_lx" set in SDR1", - value & ~sdr_mask); + qemu_log_mask(LOG_GUEST_ERROR, "Invalid bits 0x"TARGET_FMT_lx + " set in SDR1", value & ~sdr_mask); value &= sdr_mask; } if (htabsize > 28) { - error_report("Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1", - htabsize); + qemu_log_mask(LOG_GUEST_ERROR, "Invalid HTABSIZE 0x" TARGET_FMT_lx + " stored in SDR1", htabsize); return; } } @@ -92,3 +94,61 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value) env->spr[SPR_SDR1] = value; } #endif /* CONFIG_SOFTMMU */ + +/* GDBstub can read and write MSR... */ +void ppc_store_msr(CPUPPCState *env, target_ulong value) +{ + hreg_store_msr(env, value, 0); +} + +void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env = &cpu->env; + + env->spr[SPR_LPCR] = val & pcc->lpcr_mask; + /* The gtse bit affects hflags */ + hreg_compute_hflags(env); +} + +static inline void fpscr_set_rounding_mode(CPUPPCState *env) +{ + int rnd_type; + + /* Set rounding mode */ + switch (fpscr_rn) { + case 0: + /* Best approximation (round to nearest) */ + rnd_type = float_round_nearest_even; + break; + case 1: + /* Smaller magnitude (round toward zero) */ + rnd_type = float_round_to_zero; + break; + case 2: + /* Round toward +infinite */ + rnd_type = float_round_up; + break; + default: + case 3: + /* Round toward -infinite */ + rnd_type = float_round_down; + break; + } + set_float_rounding_mode(rnd_type, &env->fp_status); +} + +void ppc_store_fpscr(CPUPPCState *env, target_ulong val) +{ + val &= ~(FP_VX | FP_FEX); + if (val & FPSCR_IX) { + val |= FP_VX; + } + if ((val >> FPSCR_XX) & (val >> FPSCR_XE) & 0x1f) { + val |= FP_FEX; + } + env->fpscr = val; + if (tcg_enabled()) { + fpscr_set_rounding_mode(env); + } +} diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index cab33a3680..b4de0db7ff 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -144,6 +144,7 @@ enum { POWERPC_EXCP_ALIGN_PROT = 0x04, /* Access cross protection boundary */ POWERPC_EXCP_ALIGN_BAT = 0x05, /* Access cross a BAT/seg boundary */ POWERPC_EXCP_ALIGN_CACHE = 0x06, /* Impossible dcbz access */ + POWERPC_EXCP_ALIGN_INSN = 0x07, /* Pref. insn x-ing 64-byte boundary */ /* Exception subtypes for POWERPC_EXCP_PROGRAM */ /* FP exceptions */ POWERPC_EXCP_FP = 0x10, @@ -675,11 +676,11 @@ enum { #define fpscr_ni (((env->fpscr) >> FPSCR_NI) & 0x1) #define fpscr_rn (((env->fpscr) >> FPSCR_RN0) & 0x3) /* Invalid operation exception summary */ -#define fpscr_ix ((env->fpscr) & ((1 << FPSCR_VXSNAN) | (1 << FPSCR_VXISI) | \ - (1 << FPSCR_VXIDI) | (1 << FPSCR_VXZDZ) | \ - (1 << FPSCR_VXIMZ) | (1 << FPSCR_VXVC) | \ - (1 << FPSCR_VXSOFT) | (1 << FPSCR_VXSQRT) | \ - (1 << FPSCR_VXCVI))) +#define FPSCR_IX ((1 << FPSCR_VXSNAN) | (1 << FPSCR_VXISI) | \ + (1 << FPSCR_VXIDI) | (1 << FPSCR_VXZDZ) | \ + (1 << FPSCR_VXIMZ) | (1 << FPSCR_VXVC) | \ + (1 << FPSCR_VXSOFT) | (1 << FPSCR_VXSQRT) | \ + (1 << FPSCR_VXCVI)) /* exception summary */ #define fpscr_ex (((env->fpscr) >> FPSCR_XX) & 0x1F) /* enabled exception summary */ @@ -1256,7 +1257,6 @@ DECLARE_OBJ_CHECKERS(PPCVirtualHypervisor, PPCVirtualHypervisorClass, void ppc_cpu_do_interrupt(CPUState *cpu); bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req); void ppc_cpu_dump_state(CPUState *cpu, FILE *f, int flags); -void ppc_cpu_dump_statistics(CPUState *cpu, int flags); hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int ppc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int ppc_cpu_gdb_read_register_apple(CPUState *cpu, GByteArray *buf, int reg); @@ -1290,7 +1290,6 @@ bool ppc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, #if !defined(CONFIG_USER_ONLY) void ppc_store_sdr1(CPUPPCState *env, target_ulong value); -void ppc_store_ptcr(CPUPPCState *env, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ void ppc_store_msr(CPUPPCState *env, target_ulong value); void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val); @@ -1334,7 +1333,7 @@ void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp); #endif #endif -void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask); +void ppc_store_fpscr(CPUPPCState *env, target_ulong val); void helper_hfscr_facility_check(CPUPPCState *env, uint32_t bit, const char *caller, uint32_t cause); diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 7bdb443114..d0411e7302 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -43,7 +43,6 @@ #include "fpu/softfloat.h" #include "qapi/qapi-commands-machine-target.h" -#include "exec/helper-proto.h" #include "helper_regs.h" #include "internal.h" #include "spr_tcg.h" @@ -1206,15 +1205,12 @@ static void register_BookE206_sprs(CPUPPCState *env, uint32_t mas_mask, /* TLB assist registers */ /* XXX : not implemented */ for (i = 0; i < 8; i++) { - void (*uea_write)(DisasContext *ctx, int sprn, int gprn) = - &spr_write_generic32; - if (i == 2 && (mas_mask & (1 << i)) && (env->insns_flags & PPC_64B)) { - uea_write = &spr_write_generic; - } if (mas_mask & (1 << i)) { spr_register(env, mas_sprn[i], mas_names[i], SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, uea_write, + &spr_read_generic, + (i == 2 && (env->insns_flags & PPC_64B)) + ? &spr_write_generic : &spr_write_generic32, 0x00000000); } } @@ -8545,45 +8541,6 @@ static void init_ppc_proc(PowerPCCPU *cpu) } } -#if defined(PPC_DUMP_CPU) -static void dump_ppc_sprs(CPUPPCState *env) -{ - ppc_spr_t *spr; -#if !defined(CONFIG_USER_ONLY) - uint32_t sr, sw; -#endif - uint32_t ur, uw; - int i, j, n; - - printf("Special purpose registers:\n"); - for (i = 0; i < 32; i++) { - for (j = 0; j < 32; j++) { - n = (i << 5) | j; - spr = &env->spr_cb[n]; - uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS; - ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS; -#if !defined(CONFIG_USER_ONLY) - sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS; - sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS; - if (sw || sr || uw || ur) { - printf("SPR: %4d (%03x) %-8s s%c%c u%c%c\n", - (i << 5) | j, (i << 5) | j, spr->name, - sw ? 'w' : '-', sr ? 'r' : '-', - uw ? 'w' : '-', ur ? 'r' : '-'); - } -#else - if (uw || ur) { - printf("SPR: %4d (%03x) %-8s u%c%c\n", - (i << 5) | j, (i << 5) | j, spr->name, - uw ? 'w' : '-', ur ? 'r' : '-'); - } -#endif - } - } - fflush(stdout); - fflush(stderr); -} -#endif static void ppc_cpu_realize(DeviceState *dev, Error **errp) { @@ -8620,172 +8577,6 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp) pcc->parent_realize(dev, errp); -#if defined(PPC_DUMP_CPU) - { - CPUPPCState *env = &cpu->env; - const char *mmu_model, *excp_model, *bus_model; - switch (env->mmu_model) { - case POWERPC_MMU_32B: - mmu_model = "PowerPC 32"; - break; - case POWERPC_MMU_SOFT_6xx: - mmu_model = "PowerPC 6xx/7xx with software driven TLBs"; - break; - case POWERPC_MMU_SOFT_74xx: - mmu_model = "PowerPC 74xx with software driven TLBs"; - break; - case POWERPC_MMU_SOFT_4xx: - mmu_model = "PowerPC 4xx with software driven TLBs"; - break; - case POWERPC_MMU_SOFT_4xx_Z: - mmu_model = "PowerPC 4xx with software driven TLBs " - "and zones protections"; - break; - case POWERPC_MMU_REAL: - mmu_model = "PowerPC real mode only"; - break; - case POWERPC_MMU_MPC8xx: - mmu_model = "PowerPC MPC8xx"; - break; - case POWERPC_MMU_BOOKE: - mmu_model = "PowerPC BookE"; - break; - case POWERPC_MMU_BOOKE206: - mmu_model = "PowerPC BookE 2.06"; - break; - case POWERPC_MMU_601: - mmu_model = "PowerPC 601"; - break; -#if defined(TARGET_PPC64) - case POWERPC_MMU_64B: - mmu_model = "PowerPC 64"; - break; -#endif - default: - mmu_model = "Unknown or invalid"; - break; - } - switch (env->excp_model) { - case POWERPC_EXCP_STD: - excp_model = "PowerPC"; - break; - case POWERPC_EXCP_40x: - excp_model = "PowerPC 40x"; - break; - case POWERPC_EXCP_601: - excp_model = "PowerPC 601"; - break; - case POWERPC_EXCP_602: - excp_model = "PowerPC 602"; - break; - case POWERPC_EXCP_603: - excp_model = "PowerPC 603"; - break; - case POWERPC_EXCP_603E: - excp_model = "PowerPC 603e"; - break; - case POWERPC_EXCP_604: - excp_model = "PowerPC 604"; - break; - case POWERPC_EXCP_7x0: - excp_model = "PowerPC 740/750"; - break; - case POWERPC_EXCP_7x5: - excp_model = "PowerPC 745/755"; - break; - case POWERPC_EXCP_74xx: - excp_model = "PowerPC 74xx"; - break; - case POWERPC_EXCP_BOOKE: - excp_model = "PowerPC BookE"; - break; -#if defined(TARGET_PPC64) - case POWERPC_EXCP_970: - excp_model = "PowerPC 970"; - break; -#endif - default: - excp_model = "Unknown or invalid"; - break; - } - switch (env->bus_model) { - case PPC_FLAGS_INPUT_6xx: - bus_model = "PowerPC 6xx"; - break; - case PPC_FLAGS_INPUT_BookE: - bus_model = "PowerPC BookE"; - break; - case PPC_FLAGS_INPUT_405: - bus_model = "PowerPC 405"; - break; - case PPC_FLAGS_INPUT_401: - bus_model = "PowerPC 401/403"; - break; - case PPC_FLAGS_INPUT_RCPU: - bus_model = "RCPU / MPC8xx"; - break; -#if defined(TARGET_PPC64) - case PPC_FLAGS_INPUT_970: - bus_model = "PowerPC 970"; - break; -#endif - default: - bus_model = "Unknown or invalid"; - break; - } - printf("PowerPC %-12s : PVR %08x MSR %016" PRIx64 "\n" - " MMU model : %s\n", - object_class_get_name(OBJECT_CLASS(pcc)), - pcc->pvr, pcc->msr_mask, mmu_model); -#if !defined(CONFIG_USER_ONLY) - if (env->tlb.tlb6) { - printf(" %d %s TLB in %d ways\n", - env->nb_tlb, env->id_tlbs ? "splitted" : "merged", - env->nb_ways); - } -#endif - printf(" Exceptions model : %s\n" - " Bus model : %s\n", - excp_model, bus_model); - printf(" MSR features :\n"); - if (env->flags & POWERPC_FLAG_SPE) { - printf(" signal processing engine enable" - "\n"); - } else if (env->flags & POWERPC_FLAG_VRE) { - printf(" vector processor enable\n"); - } - if (env->flags & POWERPC_FLAG_TGPR) { - printf(" temporary GPRs\n"); - } else if (env->flags & POWERPC_FLAG_CE) { - printf(" critical input enable\n"); - } - if (env->flags & POWERPC_FLAG_SE) { - printf(" single-step trace mode\n"); - } else if (env->flags & POWERPC_FLAG_DWE) { - printf(" debug wait enable\n"); - } else if (env->flags & POWERPC_FLAG_UBLE) { - printf(" user BTB lock enable\n"); - } - if (env->flags & POWERPC_FLAG_BE) { - printf(" branch-step trace mode\n"); - } else if (env->flags & POWERPC_FLAG_DE) { - printf(" debug interrupt enable\n"); - } - if (env->flags & POWERPC_FLAG_PX) { - printf(" inclusive protection\n"); - } else if (env->flags & POWERPC_FLAG_PMM) { - printf(" performance monitor mark\n"); - } - if (env->flags == POWERPC_FLAG_NONE) { - printf(" none\n"); - } - printf(" Time-base/decrementer clock source: %s\n", - env->flags & POWERPC_FLAG_RTC_CLK ? "RTC clock" : "bus clock"); - dump_ppc_insns(env); - dump_ppc_sprs(env); - fflush(stdout); - } -#endif return; unrealize: @@ -9311,7 +9102,6 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) cc->class_by_name = ppc_cpu_class_by_name; cc->has_work = ppc_cpu_has_work; cc->dump_state = ppc_cpu_dump_state; - cc->dump_statistics = ppc_cpu_dump_statistics; cc->set_pc = ppc_cpu_set_pc; cc->gdb_read_register = ppc_cpu_gdb_read_register; cc->gdb_write_register = ppc_cpu_gdb_write_register; diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index f4f15279eb..fd147e2a37 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -19,12 +19,15 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "cpu.h" -#include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" #include "internal.h" #include "helper_regs.h" +#ifdef CONFIG_TCG +#include "exec/helper-proto.h" +#include "exec/cpu_ldst.h" +#endif + /* #define DEBUG_OP */ /* #define DEBUG_SOFTWARE_TLB */ /* #define DEBUG_EXCEPTIONS */ @@ -67,18 +70,6 @@ static inline void dump_syscall(CPUPPCState *env) ppc_dump_gpr(env, 8), env->nip); } -static inline void dump_syscall_vectored(CPUPPCState *env) -{ - qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 - " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64 - " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64 - " nip=" TARGET_FMT_lx "\n", - ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), - ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), - ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7), - ppc_dump_gpr(env, 8), env->nip); -} - static inline void dump_hcall(CPUPPCState *env) { qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64 @@ -330,7 +321,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) CPUPPCState *env = &cpu->env; target_ulong msr, new_msr, vector; int srr0, srr1, asrr0, asrr1, lev = -1; - bool lpes0; qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx " => %08x (%02x)\n", env->nip, excp, env->error_code); @@ -363,27 +353,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } /* - * Exception targeting modifiers - * - * LPES0 is supported on POWER7/8/9 - * LPES1 is not supported (old iSeries mode) - * - * On anything else, we behave as if LPES0 is 1 - * (externals don't alter MSR:HV) - */ -#if defined(TARGET_PPC64) - if (excp_model == POWERPC_EXCP_POWER7 || - excp_model == POWERPC_EXCP_POWER8 || - excp_model == POWERPC_EXCP_POWER9 || - excp_model == POWERPC_EXCP_POWER10) { - lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); - } else -#endif /* defined(TARGET_PPC64) */ - { - lpes0 = true; - } - - /* * Hypervisor emulation assistance interrupt only exists on server * arch 2.05 server or later. We also don't want to generate it if * we don't have HVB in msr_mask (PAPR mode). @@ -470,8 +439,32 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) msr |= env->error_code; break; case POWERPC_EXCP_EXTERNAL: /* External input */ + { + bool lpes0; + cs = CPU(cpu); + /* + * Exception targeting modifiers + * + * LPES0 is supported on POWER7/8/9 + * LPES1 is not supported (old iSeries mode) + * + * On anything else, we behave as if LPES0 is 1 + * (externals don't alter MSR:HV) + */ +#if defined(TARGET_PPC64) + if (excp_model == POWERPC_EXCP_POWER7 || + excp_model == POWERPC_EXCP_POWER8 || + excp_model == POWERPC_EXCP_POWER9 || + excp_model == POWERPC_EXCP_POWER10) { + lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); + } else +#endif /* defined(TARGET_PPC64) */ + { + lpes0 = true; + } + if (!lpes0) { new_msr |= (target_ulong)MSR_HVB; new_msr |= env->msr & ((target_ulong)1 << MSR_RI); @@ -483,6 +476,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack); } break; + } case POWERPC_EXCP_ALIGN: /* Alignment exception */ /* Get rS/rD and rA from faulting opcode */ /* @@ -558,7 +552,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) break; case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */ lev = env->error_code; - dump_syscall_vectored(env); + dump_syscall(env); env->nip += 4; new_msr |= env->msr & ((target_ulong)1 << MSR_EE); new_msr |= env->msr & ((target_ulong)1 << MSR_RI); @@ -695,52 +689,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) "is not implemented yet !\n"); break; case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ - switch (excp_model) { - case POWERPC_EXCP_602: - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - goto tlb_miss_tgpr; - case POWERPC_EXCP_7x5: - goto tlb_miss; - case POWERPC_EXCP_74xx: - goto tlb_miss_74xx; - default: - cpu_abort(cs, "Invalid instruction TLB miss exception\n"); - break; - } - break; case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ - switch (excp_model) { - case POWERPC_EXCP_602: - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - goto tlb_miss_tgpr; - case POWERPC_EXCP_7x5: - goto tlb_miss; - case POWERPC_EXCP_74xx: - goto tlb_miss_74xx; - default: - cpu_abort(cs, "Invalid data load TLB miss exception\n"); - break; - } - break; case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ switch (excp_model) { case POWERPC_EXCP_602: case POWERPC_EXCP_603: case POWERPC_EXCP_603E: case POWERPC_EXCP_G2: - tlb_miss_tgpr: /* Swap temporary saved registers with GPRs */ if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { new_msr |= (target_ulong)1 << MSR_TGPR; hreg_swap_gpr_tgpr(env); } - goto tlb_miss; + /* fall through */ case POWERPC_EXCP_7x5: - tlb_miss: #if defined(DEBUG_SOFTWARE_TLB) if (qemu_log_enabled()) { const char *es; @@ -775,7 +737,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; break; case POWERPC_EXCP_74xx: - tlb_miss_74xx: #if defined(DEBUG_SOFTWARE_TLB) if (qemu_log_enabled()) { const char *es; @@ -805,7 +766,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) msr |= env->error_code; /* key bit */ break; default: - cpu_abort(cs, "Invalid data store TLB miss exception\n"); + cpu_abort(cs, "Invalid TLB miss exception\n"); break; } break; @@ -1208,6 +1169,7 @@ void raise_exception_ra(CPUPPCState *env, uint32_t exception, raise_exception_err_ra(env, exception, 0, raddr); } +#ifdef CONFIG_TCG void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, uint32_t error_code) { @@ -1218,8 +1180,10 @@ void helper_raise_exception(CPUPPCState *env, uint32_t exception) { raise_exception_err_ra(env, exception, 0, 0); } +#endif #if !defined(CONFIG_USER_ONLY) +#ifdef CONFIG_TCG void helper_store_msr(CPUPPCState *env, target_ulong val) { uint32_t excp = hreg_store_msr(env, val, 0); @@ -1259,6 +1223,7 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) (env->spr[SPR_PSSCR] & PSSCR_EC); } #endif /* defined(TARGET_PPC64) */ +#endif /* CONFIG_TCG */ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) { @@ -1293,6 +1258,7 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) check_tlb_flush(env, false); } +#ifdef CONFIG_TCG void helper_rfi(CPUPPCState *env) { do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); @@ -1345,8 +1311,10 @@ void helper_rfmci(CPUPPCState *env) /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); } -#endif +#endif /* CONFIG_TCG */ +#endif /* !defined(CONFIG_USER_ONLY) */ +#ifdef CONFIG_TCG void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, uint32_t flags) { @@ -1374,11 +1342,13 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, } } #endif +#endif #if !defined(CONFIG_USER_ONLY) /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ +#ifdef CONFIG_TCG void helper_rfsvc(CPUPPCState *env) { do_rfi(env, env->lr, env->ctr & 0x0000FFFF); @@ -1523,8 +1493,10 @@ void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb) book3s_msgsnd_common(pir, PPC_INTERRUPT_DOORBELL); } #endif +#endif /* CONFIG_TCG */ #endif +#ifdef CONFIG_TCG void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) @@ -1540,3 +1512,4 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, env->error_code = insn & 0x03FF0000; cpu_loop_exit(cs); } +#endif diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 44315fca0b..c4896cecc8 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -383,247 +383,35 @@ static inline void float_inexact_excp(CPUPPCState *env) } } -static inline void fpscr_set_rounding_mode(CPUPPCState *env) -{ - int rnd_type; - - /* Set rounding mode */ - switch (fpscr_rn) { - case 0: - /* Best approximation (round to nearest) */ - rnd_type = float_round_nearest_even; - break; - case 1: - /* Smaller magnitude (round toward zero) */ - rnd_type = float_round_to_zero; - break; - case 2: - /* Round toward +infinite */ - rnd_type = float_round_up; - break; - default: - case 3: - /* Round toward -infinite */ - rnd_type = float_round_down; - break; - } - set_float_rounding_mode(rnd_type, &env->fp_status); -} - void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit) { - int prev; - - prev = (env->fpscr >> bit) & 1; - env->fpscr &= ~(1 << bit); - if (prev == 1) { - switch (bit) { - case FPSCR_RN1: - case FPSCR_RN0: - fpscr_set_rounding_mode(env); - break; - case FPSCR_VXSNAN: - case FPSCR_VXISI: - case FPSCR_VXIDI: - case FPSCR_VXZDZ: - case FPSCR_VXIMZ: - case FPSCR_VXVC: - case FPSCR_VXSOFT: - case FPSCR_VXSQRT: - case FPSCR_VXCVI: - if (!fpscr_ix) { - /* Set VX bit to zero */ - env->fpscr &= ~FP_VX; - } - break; - case FPSCR_OX: - case FPSCR_UX: - case FPSCR_ZX: - case FPSCR_XX: - case FPSCR_VE: - case FPSCR_OE: - case FPSCR_UE: - case FPSCR_ZE: - case FPSCR_XE: - if (!fpscr_eex) { - /* Set the FEX bit */ - env->fpscr &= ~FP_FEX; - } - break; - default: - break; - } + uint32_t mask = 1u << bit; + if (env->fpscr & mask) { + ppc_store_fpscr(env, env->fpscr & ~(target_ulong)mask); } } void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) { - CPUState *cs = env_cpu(env); - int prev; - - prev = (env->fpscr >> bit) & 1; - env->fpscr |= 1 << bit; - if (prev == 0) { - switch (bit) { - case FPSCR_VX: - env->fpscr |= FP_FX; - if (fpscr_ve) { - goto raise_ve; - } - break; - case FPSCR_OX: - env->fpscr |= FP_FX; - if (fpscr_oe) { - goto raise_oe; - } - break; - case FPSCR_UX: - env->fpscr |= FP_FX; - if (fpscr_ue) { - goto raise_ue; - } - break; - case FPSCR_ZX: - env->fpscr |= FP_FX; - if (fpscr_ze) { - goto raise_ze; - } - break; - case FPSCR_XX: - env->fpscr |= FP_FX; - if (fpscr_xe) { - goto raise_xe; - } - break; - case FPSCR_VXSNAN: - case FPSCR_VXISI: - case FPSCR_VXIDI: - case FPSCR_VXZDZ: - case FPSCR_VXIMZ: - case FPSCR_VXVC: - case FPSCR_VXSOFT: - case FPSCR_VXSQRT: - case FPSCR_VXCVI: - env->fpscr |= FP_VX; - env->fpscr |= FP_FX; - if (fpscr_ve != 0) { - goto raise_ve; - } - break; - case FPSCR_VE: - if (fpscr_vx != 0) { - raise_ve: - env->error_code = POWERPC_EXCP_FP; - if (fpscr_vxsnan) { - env->error_code |= POWERPC_EXCP_FP_VXSNAN; - } - if (fpscr_vxisi) { - env->error_code |= POWERPC_EXCP_FP_VXISI; - } - if (fpscr_vxidi) { - env->error_code |= POWERPC_EXCP_FP_VXIDI; - } - if (fpscr_vxzdz) { - env->error_code |= POWERPC_EXCP_FP_VXZDZ; - } - if (fpscr_vximz) { - env->error_code |= POWERPC_EXCP_FP_VXIMZ; - } - if (fpscr_vxvc) { - env->error_code |= POWERPC_EXCP_FP_VXVC; - } - if (fpscr_vxsoft) { - env->error_code |= POWERPC_EXCP_FP_VXSOFT; - } - if (fpscr_vxsqrt) { - env->error_code |= POWERPC_EXCP_FP_VXSQRT; - } - if (fpscr_vxcvi) { - env->error_code |= POWERPC_EXCP_FP_VXCVI; - } - goto raise_excp; - } - break; - case FPSCR_OE: - if (fpscr_ox != 0) { - raise_oe: - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; - goto raise_excp; - } - break; - case FPSCR_UE: - if (fpscr_ux != 0) { - raise_ue: - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; - goto raise_excp; - } - break; - case FPSCR_ZE: - if (fpscr_zx != 0) { - raise_ze: - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX; - goto raise_excp; - } - break; - case FPSCR_XE: - if (fpscr_xx != 0) { - raise_xe: - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; - goto raise_excp; - } - break; - case FPSCR_RN1: - case FPSCR_RN0: - fpscr_set_rounding_mode(env); - break; - default: - break; - raise_excp: - /* Update the floating-point enabled exception summary */ - env->fpscr |= FP_FEX; - /* We have to update Rc1 before raising the exception */ - cs->exception_index = POWERPC_EXCP_PROGRAM; - break; - } + uint32_t mask = 1u << bit; + if (!(env->fpscr & mask)) { + ppc_store_fpscr(env, env->fpscr | mask); } } -void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) +void helper_store_fpscr(CPUPPCState *env, uint64_t val, uint32_t nibbles) { - CPUState *cs = env_cpu(env); - target_ulong prev, new; + target_ulong mask = 0; int i; - prev = env->fpscr; - new = (target_ulong)arg; - new &= ~(FP_FEX | FP_VX); - new |= prev & (FP_FEX | FP_VX); + /* TODO: push this extension back to translation time */ for (i = 0; i < sizeof(target_ulong) * 2; i++) { - if (mask & (1 << i)) { - env->fpscr &= ~(0xFLL << (4 * i)); - env->fpscr |= new & (0xFLL << (4 * i)); + if (nibbles & (1 << i)) { + mask |= (target_ulong) 0xf << (4 * i); } } - /* Update VX and FEX */ - if (fpscr_ix != 0) { - env->fpscr |= FP_VX; - } else { - env->fpscr &= ~FP_VX; - } - if ((fpscr_ex & fpscr_eex) != 0) { - env->fpscr |= FP_FEX; - cs->exception_index = POWERPC_EXCP_PROGRAM; - /* XXX: we should compute it properly */ - env->error_code = POWERPC_EXCP_FP; - } else { - env->fpscr &= ~FP_FEX; - } - fpscr_set_rounding_mode(env); -} - -void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) -{ - helper_store_fpscr(env, arg, mask); + val = (val & mask) | (env->fpscr & ~mask); + ppc_store_fpscr(env, val); } static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) @@ -822,6 +610,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, int rounding_mode) { CPU_DoubleU farg; + FloatRoundMode old_rounding_mode = get_float_rounding_mode(&env->fp_status); farg.ll = arg; @@ -834,8 +623,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, float_flag_inexact; set_float_rounding_mode(rounding_mode, &env->fp_status); farg.ll = float64_round_to_int(farg.d, &env->fp_status); - /* Restore rounding mode from FPSCR */ - fpscr_set_rounding_mode(env); + set_float_rounding_mode(old_rounding_mode, &env->fp_status); /* fri* does not set FPSCR[XX] */ if (!inexact) { @@ -3136,8 +2924,10 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ ppc_vsr_t t = *xt; \ int i; \ + FloatRoundMode curr_rounding_mode; \ \ if (rmode != FLOAT_ROUND_CURRENT) { \ + curr_rounding_mode = get_float_rounding_mode(&env->fp_status); \ set_float_rounding_mode(rmode, &env->fp_status); \ } \ \ @@ -3160,7 +2950,7 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ * mode from FPSCR \ */ \ if (rmode != FLOAT_ROUND_CURRENT) { \ - fpscr_set_rounding_mode(env); \ + set_float_rounding_mode(curr_rounding_mode, &env->fp_status); \ env->fp_status.float_exception_flags &= ~float_flag_inexact; \ } \ \ diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index 9339e7eafe..09ff1328d4 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/gdbstub.h" -#include "exec/helper-proto.h" #include "internal.h" static int ppc_gdb_register_len_apple(int n) @@ -272,7 +271,7 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) break; case 70: /* fpscr */ - store_fpscr(env, ldtul_p(mem_buf), 0xffffffff); + ppc_store_fpscr(env, ldtul_p(mem_buf)); break; } } @@ -322,7 +321,7 @@ int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n) break; case 70 + 32: /* fpscr */ - store_fpscr(env, ldq_p(mem_buf), 0xffffffff); + ppc_store_fpscr(env, ldq_p(mem_buf)); break; } } @@ -475,7 +474,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, 4); - store_fpscr(env, ldl_p(mem_buf), 0xffffffff); + ppc_store_fpscr(env, ldl_p(mem_buf)); return 4; } return 0; diff --git a/target/ppc/helper.h b/target/ppc/helper.h index ea9f2a236c..c517b9f025 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -46,6 +46,7 @@ DEF_HELPER_4(divwe, tl, env, tl, tl, i32) DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_2(cmpb, TCG_CALL_NO_RWG_SE, tl, tl, tl) DEF_HELPER_3(sraw, tl, env, tl, tl) +DEF_HELPER_FLAGS_2(cfuged, TCG_CALL_NO_RWG_SE, i64, i64, i64) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_2(cmpeqb, TCG_CALL_NO_RWG_SE, i32, tl, tl) DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode new file mode 100644 index 0000000000..9fd8d6b817 --- /dev/null +++ b/target/ppc/insn32.decode @@ -0,0 +1,126 @@ +# +# Power ISA decode for 32-bit insns (opcode space 0) +# +# Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. +# + +&D rt ra si:int64_t +@D ...... rt:5 ra:5 si:s16 &D + +&D_bf bf l:bool ra imm +@D_bfs ...... bf:3 - l:1 ra:5 imm:s16 &D_bf +@D_bfu ...... bf:3 - l:1 ra:5 imm:16 &D_bf + +%ds_si 2:s14 !function=times_4 +@DS ...... rt:5 ra:5 .............. .. &D si=%ds_si + +&DX rt d +%dx_d 6:s10 16:5 0:1 +@DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d + +&VX vrt vra vrb +@VX ...... vrt:5 vra:5 vrb:5 .......... . &VX + +&X rt ra rb +@X ...... rt:5 ra:5 rb:5 .......... . &X + +&X_bi rt bi +@X_bi ...... rt:5 bi:5 ----- .......... - &X_bi + +&X_bfl bf l:bool ra rb +@X_bfl ...... bf:3 - l:1 ra:5 rb:5 ..........- &X_bfl + +### Fixed-Point Load Instructions + +LBZ 100010 ..... ..... ................ @D +LBZU 100011 ..... ..... ................ @D +LBZX 011111 ..... ..... ..... 0001010111 - @X +LBZUX 011111 ..... ..... ..... 0001110111 - @X + +LHZ 101000 ..... ..... ................ @D +LHZU 101001 ..... ..... ................ @D +LHZX 011111 ..... ..... ..... 0100010111 - @X +LHZUX 011111 ..... ..... ..... 0100110111 - @X + +LHA 101010 ..... ..... ................ @D +LHAU 101011 ..... ..... ................ @D +LHAX 011111 ..... ..... ..... 0101010111 - @X +LHAXU 011111 ..... ..... ..... 0101110111 - @X + +LWZ 100000 ..... ..... ................ @D +LWZU 100001 ..... ..... ................ @D +LWZX 011111 ..... ..... ..... 0000010111 - @X +LWZUX 011111 ..... ..... ..... 0000110111 - @X + +LWA 111010 ..... ..... ..............10 @DS +LWAX 011111 ..... ..... ..... 0101010101 - @X +LWAUX 011111 ..... ..... ..... 0101110101 - @X + +LD 111010 ..... ..... ..............00 @DS +LDU 111010 ..... ..... ..............01 @DS +LDX 011111 ..... ..... ..... 0000010101 - @X +LDUX 011111 ..... ..... ..... 0000110101 - @X + +### Fixed-Point Store Instructions + +STB 100110 ..... ..... ................ @D +STBU 100111 ..... ..... ................ @D +STBX 011111 ..... ..... ..... 0011010111 - @X +STBUX 011111 ..... ..... ..... 0011110111 - @X + +STH 101100 ..... ..... ................ @D +STHU 101101 ..... ..... ................ @D +STHX 011111 ..... ..... ..... 0110010111 - @X +STHUX 011111 ..... ..... ..... 0110110111 - @X + +STW 100100 ..... ..... ................ @D +STWU 100101 ..... ..... ................ @D +STWX 011111 ..... ..... ..... 0010010111 - @X +STWUX 011111 ..... ..... ..... 0010110111 - @X + +STD 111110 ..... ..... ..............00 @DS +STDU 111110 ..... ..... ..............01 @DS +STDX 011111 ..... ..... ..... 0010010101 - @X +STDUX 011111 ..... ..... ..... 0010110101 - @X + +### Fixed-Point Compare Instructions + +CMP 011111 ... - . ..... ..... 0000000000 - @X_bfl +CMPL 011111 ... - . ..... ..... 0000100000 - @X_bfl +CMPI 001011 ... - . ..... ................ @D_bfs +CMPLI 001010 ... - . ..... ................ @D_bfu + +### Fixed-Point Arithmetic Instructions + +ADDI 001110 ..... ..... ................ @D +ADDIS 001111 ..... ..... ................ @D + +ADDPCIS 010011 ..... ..... .......... 00010 . @DX + +## Fixed-Point Logical Instructions + +CFUGED 011111 ..... ..... ..... 0011011100 - @X + +### Move To/From System Register Instructions + +SETBC 011111 ..... ..... ----- 0110000000 - @X_bi +SETBCR 011111 ..... ..... ----- 0110100000 - @X_bi +SETNBC 011111 ..... ..... ----- 0111000000 - @X_bi +SETNBCR 011111 ..... ..... ----- 0111100000 - @X_bi + +## Vector Bit Manipulation Instruction + +VCFUGED 000100 ..... ..... ..... 10101001101 @VX diff --git a/target/ppc/insn64.decode b/target/ppc/insn64.decode new file mode 100644 index 0000000000..72c5944a53 --- /dev/null +++ b/target/ppc/insn64.decode @@ -0,0 +1,124 @@ +# +# Power ISA decode for 64-bit prefixed insns (opcode space 0 and 1) +# +# Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. +# + +# Format MLS:D and 8LS:D +&PLS_D rt ra si:int64_t r:bool +%pls_si 32:s18 0:16 +@PLS_D ...... .. ... r:1 .. .................. \ + ...... rt:5 ra:5 ................ \ + &PLS_D si=%pls_si + +### Fixed-Point Load Instructions + +PLBZ 000001 10 0--.-- .................. \ + 100010 ..... ..... ................ @PLS_D +PLHZ 000001 10 0--.-- .................. \ + 101000 ..... ..... ................ @PLS_D +PLHA 000001 10 0--.-- .................. \ + 101010 ..... ..... ................ @PLS_D +PLWZ 000001 10 0--.-- .................. \ + 100000 ..... ..... ................ @PLS_D +PLWA 000001 00 0--.-- .................. \ + 101001 ..... ..... ................ @PLS_D +PLD 000001 00 0--.-- .................. \ + 111001 ..... ..... ................ @PLS_D + +### Fixed-Point Store Instructions + +PSTW 000001 10 0--.-- .................. \ + 100100 ..... ..... ................ @PLS_D +PSTB 000001 10 0--.-- .................. \ + 100110 ..... ..... ................ @PLS_D +PSTH 000001 10 0--.-- .................. \ + 101100 ..... ..... ................ @PLS_D + +PSTD 000001 00 0--.-- .................. \ + 111101 ..... ..... ................ @PLS_D + +### Fixed-Point Arithmetic Instructions + +PADDI 000001 10 0--.-- .................. \ + 001110 ..... ..... ................ @PLS_D + +### Prefixed No-operation Instruction + +@PNOP 000001 11 0000-- 000000000000000000 \ + ................................ + +{ + [ + ## Invalid suffixes: Branch instruction + # bc[l][a] + INVALID ................................ \ + 010000-------------------------- @PNOP + # b[l][a] + INVALID ................................ \ + 010010-------------------------- @PNOP + # bclr[l] + INVALID ................................ \ + 010011---------------0000010000- @PNOP + # bcctr[l] + INVALID ................................ \ + 010011---------------1000010000- @PNOP + # bctar[l] + INVALID ................................ \ + 010011---------------1000110000- @PNOP + + ## Invalid suffixes: rfebb + INVALID ................................ \ + 010011---------------0010010010- @PNOP + + ## Invalid suffixes: context synchronizing other than isync + # sc + INVALID ................................ \ + 010001------------------------1- @PNOP + # scv + INVALID ................................ \ + 010001------------------------01 @PNOP + # rfscv + INVALID ................................ \ + 010011---------------0001010010- @PNOP + # rfid + INVALID ................................ \ + 010011---------------0000010010- @PNOP + # hrfid + INVALID ................................ \ + 010011---------------0100010010- @PNOP + # urfid + INVALID ................................ \ + 010011---------------0100110010- @PNOP + # stop + INVALID ................................ \ + 010011---------------0101110010- @PNOP + # mtmsr w/ L=0 + INVALID ................................ \ + 011111---------0-----0010010010- @PNOP + # mtmsrd w/ L=0 + INVALID ................................ \ + 011111---------0-----0010110010- @PNOP + + ## Invalid suffixes: Service Processor Attention + INVALID ................................ \ + 000000----------------100000000- @PNOP + ] + + ## Valid suffixes + PNOP ................................ \ + -------------------------------- @PNOP +} diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 41f8477d4b..efa833ef64 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -320,6 +320,68 @@ target_ulong helper_popcntb(target_ulong val) } #endif +uint64_t helper_cfuged(uint64_t src, uint64_t mask) +{ + /* + * Instead of processing the mask bit-by-bit from the most significant to + * the least significant bit, as described in PowerISA, we'll handle it in + * blocks of 'n' zeros/ones from LSB to MSB. To avoid the decision to use + * ctz or cto, we negate the mask at the end of the loop. + */ + target_ulong m, left = 0, right = 0; + unsigned int n, i = 64; + bool bit = false; /* tracks if we are processing zeros or ones */ + + if (mask == 0 || mask == -1) { + return src; + } + + /* Processes the mask in blocks, from LSB to MSB */ + while (i) { + /* Find how many bits we should take */ + n = ctz64(mask); + if (n > i) { + n = i; + } + + /* + * Extracts 'n' trailing bits of src and put them on the leading 'n' + * bits of 'right' or 'left', pushing down the previously extracted + * values. + */ + m = (1ll << n) - 1; + if (bit) { + right = ror64(right | (src & m), n); + } else { + left = ror64(left | (src & m), n); + } + + /* + * Discards the processed bits from 'src' and 'mask'. Note that we are + * removing 'n' trailing zeros from 'mask', but the logical shift will + * add 'n' leading zeros back, so the population count of 'mask' is kept + * the same. + */ + src >>= n; + mask >>= n; + i -= n; + bit = !bit; + mask = ~mask; + } + + /* + * At the end, right was ror'ed ctpop(mask) times. To put it back in place, + * we'll shift it more 64-ctpop(mask) times. + */ + if (bit) { + n = ctpop64(mask); + } else { + n = 64 - ctpop64(mask); + } + + return left | (right >> n); +} + /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2) diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 2b4b06eb76..f1fd3c8d04 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -218,8 +218,6 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, /* translate.c */ -/* #define PPC_DUMP_CPU */ - int ppc_fixup_cpu(PowerPCCPU *cpu); void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp); void destroy_ppc_opcodes(PowerPCCPU *cpu); diff --git a/target/ppc/meson.build b/target/ppc/meson.build index d1aa7d5d39..a4f18ff414 100644 --- a/target/ppc/meson.build +++ b/target/ppc/meson.build @@ -3,11 +3,14 @@ ppc_ss.add(files( 'cpu-models.c', 'cpu.c', 'cpu_init.c', - 'dfp_helper.c', 'excp_helper.c', - 'fpu_helper.c', 'gdbstub.c', 'helper_regs.c', +)) + +ppc_ss.add(when: 'CONFIG_TCG', if_true: files( + 'dfp_helper.c', + 'fpu_helper.c', 'int_helper.c', 'mem_helper.c', 'misc_helper.c', @@ -17,6 +20,15 @@ ppc_ss.add(files( ppc_ss.add(libdecnumber) +gen = [ + decodetree.process('insn32.decode', + extra_args: '--static-decode=decode_insn32'), + decodetree.process('insn64.decode', + extra_args: ['--static-decode=decode_insn64', + '--insnwidth=64']), +] +ppc_ss.add(gen) + ppc_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c')) ppc_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user_only_helper.c')) @@ -28,6 +40,10 @@ ppc_softmmu_ss.add(files( 'mmu_helper.c', 'monitor.c', )) +ppc_softmmu_ss.add(when: 'CONFIG_TCG', if_false: files( + 'tcg-stub.c' +)) + ppc_softmmu_ss.add(when: 'TARGET_PPC64', if_true: files( 'compat.c', 'mmu-book3s-v3.c', diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 08a31da289..c33f5f39b9 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -23,6 +23,7 @@ #include "exec/helper-proto.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" +#include "mmu-book3s-v3.h" #include "helper_regs.h" @@ -116,7 +117,28 @@ void helper_store_sdr1(CPUPPCState *env, target_ulong val) void helper_store_ptcr(CPUPPCState *env, target_ulong val) { if (env->spr[SPR_PTCR] != val) { - ppc_store_ptcr(env, val); + PowerPCCPU *cpu = env_archcpu(env); + target_ulong ptcr_mask = PTCR_PATB | PTCR_PATS; + target_ulong patbsize = val & PTCR_PATS; + + qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, val); + + assert(!cpu->vhyp); + assert(env->mmu_model & POWERPC_MMU_3_00); + + if (val & ~ptcr_mask) { + error_report("Invalid bits 0x"TARGET_FMT_lx" set in PTCR", + val & ~ptcr_mask); + val &= ptcr_mask; + } + + if (patbsize > 24) { + error_report("Invalid Partition Table size 0x" TARGET_FMT_lx + " stored in PTCR", patbsize); + return; + } + + env->spr[SPR_PTCR] = val; tlb_flush(env_cpu(env)); } } @@ -255,22 +277,6 @@ target_ulong helper_clcs(CPUPPCState *env, uint32_t arg) /*****************************************************************************/ /* Special registers manipulation */ -/* GDBstub can read and write MSR... */ -void ppc_store_msr(CPUPPCState *env, target_ulong value) -{ - hreg_store_msr(env, value, 0); -} - -void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) -{ - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - CPUPPCState *env = &cpu->env; - - env->spr[SPR_LPCR] = val & pcc->lpcr_mask; - /* The gtse bit affects hflags */ - hreg_compute_hflags(env); -} - /* * This code is lifted from MacOnLinux. It is called whenever THRM1,2 * or 3 is read an fixes up the values in such a way that will make diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c index 744a763f44..9f0a497657 100644 --- a/target/ppc/mmu-hash32.c +++ b/target/ppc/mmu-hash32.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/exec-all.h" -#include "exec/helper-proto.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" #include "internal.h" diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index f48b625f48..708dffc31b 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -21,7 +21,6 @@ #include "qemu/units.h" #include "cpu.h" #include "exec/exec-all.h" -#include "exec/helper-proto.h" #include "qemu/error-report.h" #include "qemu/qemu-print.h" #include "sysemu/hw_accel.h" @@ -33,6 +32,10 @@ #include "mmu-book3s-v3.h" #include "helper_regs.h" +#ifdef CONFIG_TCG +#include "exec/helper-proto.h" +#endif + /* #define DEBUG_SLB */ #ifdef DEBUG_SLB @@ -97,6 +100,7 @@ void dump_slb(PowerPCCPU *cpu) } } +#ifdef CONFIG_TCG void helper_slbia(CPUPPCState *env, uint32_t ih) { PowerPCCPU *cpu = env_archcpu(env); @@ -202,6 +206,7 @@ void helper_slbieg(CPUPPCState *env, target_ulong addr) { __helper_slbie(env, addr, true); } +#endif int ppc_store_slb(PowerPCCPU *cpu, target_ulong slot, target_ulong esid, target_ulong vsid) @@ -255,6 +260,7 @@ int ppc_store_slb(PowerPCCPU *cpu, target_ulong slot, return 0; } +#ifdef CONFIG_TCG static int ppc_load_slb_esid(PowerPCCPU *cpu, target_ulong rb, target_ulong *rt) { @@ -348,6 +354,7 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb) } return rt; } +#endif /* Check No-Execute or Guarded Storage */ static inline int ppc_hash64_pte_noexec_guard(PowerPCCPU *cpu, @@ -1139,12 +1146,14 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex, cpu->env.tlb_need_flush = TLB_NEED_GLOBAL_FLUSH | TLB_NEED_LOCAL_FLUSH; } +#ifdef CONFIG_TCG void helper_store_lpcr(CPUPPCState *env, target_ulong val) { PowerPCCPU *cpu = env_archcpu(env); ppc_store_lpcr(cpu, val); } +#endif void ppc_hash64_init(PowerPCCPU *cpu) { diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 7972153f23..b6d191c1d8 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/exec-all.h" -#include "exec/helper-proto.h" #include "qemu/error-report.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 37986c59ba..1ecb36e85a 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -20,13 +20,11 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "cpu.h" -#include "exec/helper-proto.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" #include "mmu-hash64.h" #include "mmu-hash32.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" #include "exec/log.h" #include "helper_regs.h" #include "qemu/error-report.h" @@ -36,6 +34,10 @@ #include "mmu-book3s-v3.h" #include "mmu-radix64.h" +#ifdef CONFIG_TCG +#include "exec/helper-proto.h" +#include "exec/cpu_ldst.h" +#endif /* #define DEBUG_MMU */ /* #define DEBUG_BATS */ /* #define DEBUG_SOFTWARE_TLB */ @@ -268,6 +270,7 @@ static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env, ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0); } +#ifdef CONFIG_TCG static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, int is_code, target_ulong pte0, target_ulong pte1) { @@ -286,6 +289,7 @@ static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, /* Store last way for LRU mechanism */ env->last_way = way; } +#endif static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, MMUAccessType access_type) @@ -626,6 +630,7 @@ static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb, return 0; } +#ifdef CONFIG_TCG /* Generic TLB search function for PowerPC embedded implementations */ static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid) @@ -646,6 +651,7 @@ static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, return ret; } +#endif /* Helpers specific to PowerPC 40x implementations */ static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env) @@ -1420,12 +1426,14 @@ static int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx, return ret; } +#ifdef CONFIG_TCG static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, MMUAccessType access_type, int type) { return get_physical_address_wtlb(env, ctx, eaddr, access_type, type, 0); } +#endif hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) { @@ -1752,6 +1760,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, return ret; } +#ifdef CONFIG_TCG /*****************************************************************************/ /* BATs management */ #if !defined(FLUSH_ALL_TLBS) @@ -1941,6 +1950,7 @@ void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value) #endif } } +#endif /*****************************************************************************/ /* TLB management */ @@ -1986,6 +1996,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env) } } +#ifdef CONFIG_TCG void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) { #if !defined(FLUSH_ALL_TLBS) @@ -2030,34 +2041,6 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) /*****************************************************************************/ /* Special registers manipulation */ -#if defined(TARGET_PPC64) -void ppc_store_ptcr(CPUPPCState *env, target_ulong value) -{ - PowerPCCPU *cpu = env_archcpu(env); - target_ulong ptcr_mask = PTCR_PATB | PTCR_PATS; - target_ulong patbsize = value & PTCR_PATS; - - qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value); - - assert(!cpu->vhyp); - assert(env->mmu_model & POWERPC_MMU_3_00); - - if (value & ~ptcr_mask) { - error_report("Invalid bits 0x"TARGET_FMT_lx" set in PTCR", - value & ~ptcr_mask); - value &= ptcr_mask; - } - - if (patbsize > 24) { - error_report("Invalid Partition Table size 0x" TARGET_FMT_lx - " stored in PTCR", patbsize); - return; - } - - env->spr[SPR_PTCR] = value; -} - -#endif /* defined(TARGET_PPC64) */ /* Segment registers load and store */ target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num) @@ -2955,6 +2938,7 @@ void helper_check_tlb_flush_global(CPUPPCState *env) { check_tlb_flush(env, true); } +#endif /* CONFIG_TCG */ /*****************************************************************************/ diff --git a/target/ppc/tcg-stub.c b/target/ppc/tcg-stub.c new file mode 100644 index 0000000000..aadcf59d26 --- /dev/null +++ b/target/ppc/tcg-stub.c @@ -0,0 +1,45 @@ +/* + * PowerPC CPU initialization for qemu. + * + * Copyright (C) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "qemu/osdep.h" +#include "cpu.h" +#include "internal.h" +#include "hw/ppc/spapr.h" + +void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp) +{ +} + +void destroy_ppc_opcodes(PowerPCCPU *cpu) +{ +} + +target_ulong softmmu_resize_hpt_prepare(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong shift) +{ + g_assert_not_reached(); +} + +target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong flags, + target_ulong shift) +{ + g_assert_not_reached(); +} diff --git a/target/ppc/translate.c b/target/ppc/translate.c index ea200f9637..f65d1e81ea 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -47,7 +47,6 @@ /* Include definitions for instructions classes and implementations flags */ /* #define PPC_DEBUG_DISAS */ -/* #define DO_PPC_STATISTICS */ #ifdef PPC_DEBUG_DISAS # define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) @@ -217,12 +216,6 @@ struct opc_handler_t { uint64_t type2; /* handler */ void (*handler)(DisasContext *ctx); -#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) - const char *oname; -#endif -#if defined(DO_PPC_STATISTICS) - uint64_t count; -#endif }; /* SPR load/store helpers */ @@ -1345,7 +1338,6 @@ typedef struct opcode_t { /*****************************************************************************/ /* PowerPC instructions table */ -#if defined(DO_PPC_STATISTICS) #define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2) \ { \ .opc1 = op1, \ @@ -1357,7 +1349,6 @@ typedef struct opcode_t { .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ - .oname = stringify(name), \ }, \ .oname = stringify(name), \ } @@ -1373,7 +1364,6 @@ typedef struct opcode_t { .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ - .oname = stringify(name), \ }, \ .oname = stringify(name), \ } @@ -1388,7 +1378,6 @@ typedef struct opcode_t { .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ - .oname = onam, \ }, \ .oname = onam, \ } @@ -1403,7 +1392,6 @@ typedef struct opcode_t { .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ - .oname = stringify(name), \ }, \ .oname = stringify(name), \ } @@ -1418,83 +1406,9 @@ typedef struct opcode_t { .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ - .oname = onam, \ }, \ .oname = onam, \ } -#else -#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2) \ -{ \ - .opc1 = op1, \ - .opc2 = op2, \ - .opc3 = op3, \ - .opc4 = 0xff, \ - .handler = { \ - .inval1 = invl, \ - .type = _typ, \ - .type2 = _typ2, \ - .handler = &gen_##name, \ - }, \ - .oname = stringify(name), \ -} -#define GEN_OPCODE_DUAL(name, op1, op2, op3, invl1, invl2, _typ, _typ2) \ -{ \ - .opc1 = op1, \ - .opc2 = op2, \ - .opc3 = op3, \ - .opc4 = 0xff, \ - .handler = { \ - .inval1 = invl1, \ - .inval2 = invl2, \ - .type = _typ, \ - .type2 = _typ2, \ - .handler = &gen_##name, \ - }, \ - .oname = stringify(name), \ -} -#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ, _typ2) \ -{ \ - .opc1 = op1, \ - .opc2 = op2, \ - .opc3 = op3, \ - .opc4 = 0xff, \ - .handler = { \ - .inval1 = invl, \ - .type = _typ, \ - .type2 = _typ2, \ - .handler = &gen_##name, \ - }, \ - .oname = onam, \ -} -#define GEN_OPCODE3(name, op1, op2, op3, op4, invl, _typ, _typ2) \ -{ \ - .opc1 = op1, \ - .opc2 = op2, \ - .opc3 = op3, \ - .opc4 = op4, \ - .handler = { \ - .inval1 = invl, \ - .type = _typ, \ - .type2 = _typ2, \ - .handler = &gen_##name, \ - }, \ - .oname = stringify(name), \ -} -#define GEN_OPCODE4(name, onam, op1, op2, op3, op4, invl, _typ, _typ2) \ -{ \ - .opc1 = op1, \ - .opc2 = op2, \ - .opc3 = op3, \ - .opc4 = op4, \ - .handler = { \ - .inval1 = invl, \ - .type = _typ, \ - .type2 = _typ2, \ - .handler = &gen_##name, \ - }, \ - .oname = onam, \ -} -#endif /* Invalid instruction */ static void gen_invalid(DisasContext *ctx) @@ -1575,54 +1489,6 @@ static inline void gen_set_Rc0(DisasContext *ctx, TCGv reg) } } -/* cmp */ -static void gen_cmp(DisasContext *ctx) -{ - if ((ctx->opcode & 0x00200000) && (ctx->insns_flags & PPC_64B)) { - gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], - 1, crfD(ctx->opcode)); - } else { - gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], - 1, crfD(ctx->opcode)); - } -} - -/* cmpi */ -static void gen_cmpi(DisasContext *ctx) -{ - if ((ctx->opcode & 0x00200000) && (ctx->insns_flags & PPC_64B)) { - gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode), - 1, crfD(ctx->opcode)); - } else { - gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode), - 1, crfD(ctx->opcode)); - } -} - -/* cmpl */ -static void gen_cmpl(DisasContext *ctx) -{ - if ((ctx->opcode & 0x00200000) && (ctx->insns_flags & PPC_64B)) { - gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], - 0, crfD(ctx->opcode)); - } else { - gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], - 0, crfD(ctx->opcode)); - } -} - -/* cmpli */ -static void gen_cmpli(DisasContext *ctx) -{ - if ((ctx->opcode & 0x00200000) && (ctx->insns_flags & PPC_64B)) { - gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode), - 0, crfD(ctx->opcode)); - } else { - gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode), - 0, crfD(ctx->opcode)); - } -} - /* cmprb - range comparison: isupper, isaplha, islower*/ static void gen_cmprb(DisasContext *ctx) { @@ -1846,19 +1712,6 @@ GEN_INT_ARITH_ADD(addex, 0x05, cpu_ov, 1, 1, 0); /* addze addze. addzeo addzeo.*/ GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, cpu_ca, 1, 1, 0) GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, cpu_ca, 1, 1, 1) -/* addi */ -static void gen_addi(DisasContext *ctx) -{ - target_long simm = SIMM(ctx->opcode); - - if (rA(ctx->opcode) == 0) { - /* li case */ - tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm); - } else { - tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], - cpu_gpr[rA(ctx->opcode)], simm); - } -} /* addic addic.*/ static inline void gen_op_addic(DisasContext *ctx, bool compute_rc0) { @@ -1878,28 +1731,6 @@ static void gen_addic_(DisasContext *ctx) gen_op_addic(ctx, 1); } -/* addis */ -static void gen_addis(DisasContext *ctx) -{ - target_long simm = SIMM(ctx->opcode); - - if (rA(ctx->opcode) == 0) { - /* lis case */ - tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm << 16); - } else { - tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], - cpu_gpr[rA(ctx->opcode)], simm << 16); - } -} - -/* addpcis */ -static void gen_addpcis(DisasContext *ctx) -{ - target_long d = DX(ctx->opcode); - - tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], ctx->base.pc_next + (d << 16)); -} - static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2, int sign, int compute_ov) { @@ -3412,7 +3243,9 @@ static void glue(gen_qemu_, stop)(DisasContext *ctx, \ tcg_gen_qemu_st_tl(val, addr, ctx->mem_idx, op); \ } +#if defined(TARGET_PPC64) || !defined(CONFIG_USER_ONLY) GEN_QEMU_STORE_TL(st8, DEF_MEMOP(MO_UB)) +#endif GEN_QEMU_STORE_TL(st16, DEF_MEMOP(MO_UW)) GEN_QEMU_STORE_TL(st32, DEF_MEMOP(MO_UL)) @@ -3436,54 +3269,6 @@ GEN_QEMU_STORE_64(st64, DEF_MEMOP(MO_Q)) GEN_QEMU_STORE_64(st64r, BSWAP_MEMOP(MO_Q)) #endif -#define GEN_LD(name, ldop, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_LDU(name, ldop, opc, type) \ -static void glue(gen_, name##u)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode))) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - if (type == PPC_64B) \ - gen_addr_imm_index(ctx, EA, 0x03); \ - else \ - gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_LDUX(name, ldop, opc2, opc3, type) \ -static void glue(gen_, name##ux)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode))) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - #define GEN_LDX_E(name, ldop, opc2, opc3, type, type2, chk) \ static void glue(gen_, name##x)(DisasContext *ctx) \ { \ @@ -3502,21 +3287,6 @@ static void glue(gen_, name##x)(DisasContext *ctx) \ #define GEN_LDX_HVRM(name, ldop, opc2, opc3, type) \ GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE, CHK_HVRM) -#define GEN_LDS(name, ldop, op, type) \ -GEN_LD(name, ldop, op | 0x20, type); \ -GEN_LDU(name, ldop, op | 0x21, type); \ -GEN_LDUX(name, ldop, 0x17, op | 0x01, type); \ -GEN_LDX(name, ldop, 0x17, op | 0x00, type) - -/* lbz lbzu lbzux lbzx */ -GEN_LDS(lbz, ld8u, 0x02, PPC_INTEGER); -/* lha lhau lhaux lhax */ -GEN_LDS(lha, ld16s, 0x0A, PPC_INTEGER); -/* lhz lhzu lhzux lhzx */ -GEN_LDS(lhz, ld16u, 0x08, PPC_INTEGER); -/* lwz lwzu lwzux lwzx */ -GEN_LDS(lwz, ld32u, 0x00, PPC_INTEGER); - #define GEN_LDEPX(name, ldop, opc2, opc3) \ static void glue(gen_, name##epx)(DisasContext *ctx) \ { \ @@ -3537,47 +3307,12 @@ GEN_LDEPX(ld, DEF_MEMOP(MO_Q), 0x1D, 0x00) #endif #if defined(TARGET_PPC64) -/* lwaux */ -GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B); -/* lwax */ -GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B); -/* ldux */ -GEN_LDUX(ld, ld64_i64, 0x15, 0x01, PPC_64B); -/* ldx */ -GEN_LDX(ld, ld64_i64, 0x15, 0x00, PPC_64B); - /* CI load/store variants */ GEN_LDX_HVRM(ldcix, ld64_i64, 0x15, 0x1b, PPC_CILDST) GEN_LDX_HVRM(lwzcix, ld32u, 0x15, 0x15, PPC_CILDST) GEN_LDX_HVRM(lhzcix, ld16u, 0x15, 0x19, PPC_CILDST) GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST) -static void gen_ld(DisasContext *ctx) -{ - TCGv EA; - if (Rc(ctx->opcode)) { - if (unlikely(rA(ctx->opcode) == 0 || - rA(ctx->opcode) == rD(ctx->opcode))) { - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); - return; - } - } - gen_set_access_type(ctx, ACCESS_INT); - EA = tcg_temp_new(); - gen_addr_imm_index(ctx, EA, 0x03); - if (ctx->opcode & 0x02) { - /* lwa (lwau is undefined) */ - gen_qemu_ld32s(ctx, cpu_gpr[rD(ctx->opcode)], EA); - } else { - /* ld - ldu */ - gen_qemu_ld64_i64(ctx, cpu_gpr[rD(ctx->opcode)], EA); - } - if (Rc(ctx->opcode)) { - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); - } - tcg_temp_free(EA); -} - /* lq */ static void gen_lq(DisasContext *ctx) { @@ -3643,52 +3378,6 @@ static void gen_lq(DisasContext *ctx) #endif /*** Integer store ***/ -#define GEN_ST(name, stop, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_STU(name, stop, opc, type) \ -static void glue(gen_, stop##u)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(rA(ctx->opcode) == 0)) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - if (type == PPC_64B) \ - gen_addr_imm_index(ctx, EA, 0x03); \ - else \ - gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - -#define GEN_STUX(name, stop, opc2, opc3, type) \ -static void glue(gen_, name##ux)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - if (unlikely(rA(ctx->opcode) == 0)) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ -} - #define GEN_STX_E(name, stop, opc2, opc3, type, type2, chk) \ static void glue(gen_, name##x)(DisasContext *ctx) \ { \ @@ -3706,19 +3395,6 @@ static void glue(gen_, name##x)(DisasContext *ctx) \ #define GEN_STX_HVRM(name, stop, opc2, opc3, type) \ GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE, CHK_HVRM) -#define GEN_STS(name, stop, op, type) \ -GEN_ST(name, stop, op | 0x20, type); \ -GEN_STU(name, stop, op | 0x21, type); \ -GEN_STUX(name, stop, 0x17, op | 0x01, type); \ -GEN_STX(name, stop, 0x17, op | 0x00, type) - -/* stb stbu stbux stbx */ -GEN_STS(stb, st8, 0x06, PPC_INTEGER); -/* sth sthu sthux sthx */ -GEN_STS(sth, st16, 0x0C, PPC_INTEGER); -/* stw stwu stwux stwx */ -GEN_STS(stw, st32, 0x04, PPC_INTEGER); - #define GEN_STEPX(name, stop, opc2, opc3) \ static void glue(gen_, name##epx)(DisasContext *ctx) \ { \ @@ -3740,8 +3416,6 @@ GEN_STEPX(std, DEF_MEMOP(MO_Q), 0x1d, 0x04) #endif #if defined(TARGET_PPC64) -GEN_STUX(std, st64_i64, 0x15, 0x05, PPC_64B); -GEN_STX(std, st64_i64, 0x15, 0x04, PPC_64B); GEN_STX_HVRM(stdcix, st64_i64, 0x15, 0x1f, PPC_CILDST) GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST) GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST) @@ -4646,8 +4320,7 @@ static void gen_lookup_and_goto_ptr(DisasContext *ctx) if (sse & GDBSTUB_SINGLE_STEP) { gen_debug_exception(ctx); } else if (sse & (CPU_SINGLE_STEP | CPU_BRANCH_STEP)) { - uint32_t excp = gen_prep_dbgex(ctx); - gen_exception(ctx, excp); + gen_helper_raise_exception(cpu_env, tcg_constant_i32(gen_prep_dbgex(ctx))); } else { tcg_gen_exit_tb(NULL, 0); } @@ -7750,11 +7423,65 @@ static inline void set_avr64(int regno, TCGv_i64 src, bool high) tcg_gen_st_i64(src, cpu_env, avr64_offset(regno, high)); } +/* + * Helpers for decodetree used by !function for decoding arguments. + */ +static int times_4(DisasContext *ctx, int x) +{ + return x * 4; +} + +/* + * Helpers for trans_* functions to check for specific insns flags. + * Use token pasting to ensure that we use the proper flag with the + * proper variable. + */ +#define REQUIRE_INSNS_FLAGS(CTX, NAME) \ + do { \ + if (((CTX)->insns_flags & PPC_##NAME) == 0) { \ + return false; \ + } \ + } while (0) + +#define REQUIRE_INSNS_FLAGS2(CTX, NAME) \ + do { \ + if (((CTX)->insns_flags2 & PPC2_##NAME) == 0) { \ + return false; \ + } \ + } while (0) + +/* Then special-case the check for 64-bit so that we elide code for ppc32. */ +#if TARGET_LONG_BITS == 32 +# define REQUIRE_64BIT(CTX) return false +#else +# define REQUIRE_64BIT(CTX) REQUIRE_INSNS_FLAGS(CTX, 64B) +#endif + +/* + * Helpers for implementing sets of trans_* functions. + * Defer the implementation of NAME to FUNC, with optional extra arguments. + */ +#define TRANS(NAME, FUNC, ...) \ + static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ + { return FUNC(ctx, a, __VA_ARGS__); } + +#define TRANS64(NAME, FUNC, ...) \ + static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ + { REQUIRE_64BIT(ctx); return FUNC(ctx, a, __VA_ARGS__); } + +/* TODO: More TRANS* helpers for extra insn_flags checks. */ + + +#include "decode-insn32.c.inc" +#include "decode-insn64.c.inc" +#include "translate/fixedpoint-impl.c.inc" + #include "translate/fp-impl.c.inc" #include "translate/vmx-impl.c.inc" #include "translate/vsx-impl.c.inc" +#include "translate/vector-impl.c.inc" #include "translate/dfp-impl.c.inc" @@ -7863,21 +7590,14 @@ GEN_HANDLER_E(brw, 0x1F, 0x1B, 0x04, 0x0000F801, PPC_NONE, PPC2_ISA310), GEN_HANDLER_E(brh, 0x1F, 0x1B, 0x06, 0x0000F801, PPC_NONE, PPC2_ISA310), #endif GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE), -GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER), -GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), -GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400001, PPC_INTEGER), -GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), #if defined(TARGET_PPC64) GEN_HANDLER_E(cmpeqb, 0x1F, 0x00, 0x07, 0x00600000, PPC_NONE, PPC2_ISA300), #endif GEN_HANDLER_E(cmpb, 0x1F, 0x1C, 0x0F, 0x00000001, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(cmprb, 0x1F, 0x00, 0x06, 0x00400001, PPC_NONE, PPC2_ISA300), GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL), -GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), -GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), -GEN_HANDLER_E(addpcis, 0x13, 0x2, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_HANDLER(mulhw, 0x1F, 0x0B, 0x02, 0x00000400, PPC_INTEGER), GEN_HANDLER(mulhwu, 0x1F, 0x0B, 0x00, 0x00000400, PPC_INTEGER), GEN_HANDLER(mullw, 0x1F, 0x0B, 0x07, 0x00000000, PPC_INTEGER), @@ -7932,7 +7652,6 @@ GEN_HANDLER2_E(extswsli1, "extswsli", 0x1F, 0x1B, 0x1B, 0x00000000, PPC_NONE, PPC2_ISA300), #endif #if defined(TARGET_PPC64) -GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B), GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX), GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B), #endif @@ -8298,34 +8017,11 @@ GEN_PPC64_R2(rldcr, 0x1E, 0x09), GEN_PPC64_R4(rldimi, 0x1E, 0x06), #endif -#undef GEN_LD -#undef GEN_LDU -#undef GEN_LDUX #undef GEN_LDX_E -#undef GEN_LDS -#define GEN_LD(name, ldop, opc, type) \ -GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_LDU(name, ldop, opc, type) \ -GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_LDUX(name, ldop, opc2, opc3, type) \ -GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type), #define GEN_LDX_E(name, ldop, opc2, opc3, type, type2, chk) \ GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2), -#define GEN_LDS(name, ldop, op, type) \ -GEN_LD(name, ldop, op | 0x20, type) \ -GEN_LDU(name, ldop, op | 0x21, type) \ -GEN_LDUX(name, ldop, 0x17, op | 0x01, type) \ -GEN_LDX(name, ldop, 0x17, op | 0x00, type) - -GEN_LDS(lbz, ld8u, 0x02, PPC_INTEGER) -GEN_LDS(lha, ld16s, 0x0A, PPC_INTEGER) -GEN_LDS(lhz, ld16u, 0x08, PPC_INTEGER) -GEN_LDS(lwz, ld32u, 0x00, PPC_INTEGER) + #if defined(TARGET_PPC64) -GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B) -GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B) -GEN_LDUX(ld, ld64_i64, 0x15, 0x01, PPC_64B) -GEN_LDX(ld, ld64_i64, 0x15, 0x00, PPC_64B) GEN_LDX_E(ldbr, ld64ur_i64, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE) /* HV/P7 and later only */ @@ -8350,31 +8046,11 @@ GEN_LDEPX(lw, DEF_MEMOP(MO_UL), 0x1F, 0x00) GEN_LDEPX(ld, DEF_MEMOP(MO_Q), 0x1D, 0x00) #endif -#undef GEN_ST -#undef GEN_STU -#undef GEN_STUX #undef GEN_STX_E -#undef GEN_STS -#define GEN_ST(name, stop, opc, type) \ -GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_STU(name, stop, opc, type) \ -GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_STUX(name, stop, opc2, opc3, type) \ -GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type), #define GEN_STX_E(name, stop, opc2, opc3, type, type2, chk) \ GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000000, type, type2), -#define GEN_STS(name, stop, op, type) \ -GEN_ST(name, stop, op | 0x20, type) \ -GEN_STU(name, stop, op | 0x21, type) \ -GEN_STUX(name, stop, 0x17, op | 0x01, type) \ -GEN_STX(name, stop, 0x17, op | 0x00, type) - -GEN_STS(stb, st8, 0x06, PPC_INTEGER) -GEN_STS(sth, st16, 0x0C, PPC_INTEGER) -GEN_STS(stw, st32, 0x04, PPC_INTEGER) + #if defined(TARGET_PPC64) -GEN_STUX(std, st64_i64, 0x15, 0x05, PPC_64B) -GEN_STX(std, st64_i64, 0x15, 0x04, PPC_64B) GEN_STX_E(stdbr, st64r_i64, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE) GEN_STX_HVRM(stdcix, st64_i64, 0x15, 0x1f, PPC_CILDST) GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST) @@ -8546,10 +8222,6 @@ static int register_direct_insn(opc_handler_t **ppc_opcodes, if (insert_in_table(ppc_opcodes, idx, handler) < 0) { printf("*** ERROR: opcode %02x already assigned in main " "opcode table\n", idx); -#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) - printf(" Registered handler '%s' - new handler '%s'\n", - ppc_opcodes[idx]->oname, handler->oname); -#endif return -1; } @@ -8570,10 +8242,6 @@ static int register_ind_in_table(opc_handler_t **table, if (!is_indirect_opcode(table[idx1])) { printf("*** ERROR: idx %02x already assigned to a direct " "opcode\n", idx1); -#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) - printf(" Registered handler '%s' - new handler '%s'\n", - ind_table(table[idx1])[idx2]->oname, handler->oname); -#endif return -1; } } @@ -8581,10 +8249,6 @@ static int register_ind_in_table(opc_handler_t **table, insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { printf("*** ERROR: opcode %02x already assigned in " "opcode table %02x\n", idx2, idx1); -#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) - printf(" Registered handler '%s' - new handler '%s'\n", - ind_table(table[idx1])[idx2]->oname, handler->oname); -#endif return -1; } @@ -8766,96 +8430,6 @@ void destroy_ppc_opcodes(PowerPCCPU *cpu) } } -#if defined(PPC_DUMP_CPU) -static void dump_ppc_insns(CPUPPCState *env) -{ - opc_handler_t **table, *handler; - const char *p, *q; - uint8_t opc1, opc2, opc3, opc4; - - printf("Instructions set:\n"); - /* opc1 is 6 bits long */ - for (opc1 = 0x00; opc1 < PPC_CPU_OPCODES_LEN; opc1++) { - table = env->opcodes; - handler = table[opc1]; - if (is_indirect_opcode(handler)) { - /* opc2 is 5 bits long */ - for (opc2 = 0; opc2 < PPC_CPU_INDIRECT_OPCODES_LEN; opc2++) { - table = env->opcodes; - handler = env->opcodes[opc1]; - table = ind_table(handler); - handler = table[opc2]; - if (is_indirect_opcode(handler)) { - table = ind_table(handler); - /* opc3 is 5 bits long */ - for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN; - opc3++) { - handler = table[opc3]; - if (is_indirect_opcode(handler)) { - table = ind_table(handler); - /* opc4 is 5 bits long */ - for (opc4 = 0; opc4 < PPC_CPU_INDIRECT_OPCODES_LEN; - opc4++) { - handler = table[opc4]; - if (handler->handler != &gen_invalid) { - printf("INSN: %02x %02x %02x %02x -- " - "(%02d %04d %02d) : %s\n", - opc1, opc2, opc3, opc4, - opc1, (opc3 << 5) | opc2, opc4, - handler->oname); - } - } - } else { - if (handler->handler != &gen_invalid) { - /* Special hack to properly dump SPE insns */ - p = strchr(handler->oname, '_'); - if (p == NULL) { - printf("INSN: %02x %02x %02x (%02d %04d) : " - "%s\n", - opc1, opc2, opc3, opc1, - (opc3 << 5) | opc2, - handler->oname); - } else { - q = "speundef"; - if ((p - handler->oname) != strlen(q) - || (memcmp(handler->oname, q, strlen(q)) - != 0)) { - /* First instruction */ - printf("INSN: %02x %02x %02x" - "(%02d %04d) : %.*s\n", - opc1, opc2 << 1, opc3, opc1, - (opc3 << 6) | (opc2 << 1), - (int)(p - handler->oname), - handler->oname); - } - if (strcmp(p + 1, q) != 0) { - /* Second instruction */ - printf("INSN: %02x %02x %02x " - "(%02d %04d) : %s\n", opc1, - (opc2 << 1) | 1, opc3, opc1, - (opc3 << 6) | (opc2 << 1) | 1, - p + 1); - } - } - } - } - } - } else { - if (handler->handler != &gen_invalid) { - printf("INSN: %02x %02x -- (%02d %04d) : %s\n", - opc1, opc2, opc1, opc2, handler->oname); - } - } - } - } else { - if (handler->handler != &gen_invalid) { - printf("INSN: %02x -- -- (%02d ----) : %s\n", - opc1, opc1, handler->oname); - } - } - } -} -#endif int ppc_fixup_cpu(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; @@ -8881,57 +8455,6 @@ int ppc_fixup_cpu(PowerPCCPU *cpu) return 0; } - -void ppc_cpu_dump_statistics(CPUState *cs, int flags) -{ -#if defined(DO_PPC_STATISTICS) - PowerPCCPU *cpu = POWERPC_CPU(cs); - opc_handler_t **t1, **t2, **t3, *handler; - int op1, op2, op3; - - t1 = cpu->env.opcodes; - for (op1 = 0; op1 < 64; op1++) { - handler = t1[op1]; - if (is_indirect_opcode(handler)) { - t2 = ind_table(handler); - for (op2 = 0; op2 < 32; op2++) { - handler = t2[op2]; - if (is_indirect_opcode(handler)) { - t3 = ind_table(handler); - for (op3 = 0; op3 < 32; op3++) { - handler = t3[op3]; - if (handler->count == 0) { - continue; - } - qemu_printf("%02x %02x %02x (%02x %04d) %16s: " - "%016" PRIx64 " %" PRId64 "\n", - op1, op2, op3, op1, (op3 << 5) | op2, - handler->oname, - handler->count, handler->count); - } - } else { - if (handler->count == 0) { - continue; - } - qemu_printf("%02x %02x (%02x %04d) %16s: " - "%016" PRIx64 " %" PRId64 "\n", - op1, op2, op1, op2, handler->oname, - handler->count, handler->count); - } - } - } else { - if (handler->count == 0) { - continue; - } - qemu_printf("%02x (%02x ) %16s: %016" PRIx64 - " %" PRId64 "\n", - op1, op1, handler->oname, - handler->count, handler->count); - } - } -#endif -} - static bool decode_legacy(PowerPCCPU *cpu, DisasContext *ctx, uint32_t insn) { opc_handler_t **table, *handler; @@ -9034,9 +8557,6 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) if (ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP)) { ctx->base.max_insns = 1; - } else { - int bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; - ctx->base.max_insns = MIN(ctx->base.max_insns, bound); } } @@ -9066,11 +8586,18 @@ static bool ppc_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, return true; } +static bool is_prefix_insn(DisasContext *ctx, uint32_t insn) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + return opc1(insn) == 1; +} + static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = cs->env_ptr; + target_ulong pc; uint32_t insn; bool ok; @@ -9078,18 +8605,34 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) LOG_DISAS("nip=" TARGET_FMT_lx " super=%d ir=%d\n", ctx->base.pc_next, ctx->mem_idx, (int)msr_ir); - ctx->cia = ctx->base.pc_next; - insn = translator_ldl_swap(env, ctx->base.pc_next, need_byteswap(ctx)); - ctx->base.pc_next += 4; + ctx->cia = pc = ctx->base.pc_next; + insn = translator_ldl_swap(env, pc, need_byteswap(ctx)); + ctx->base.pc_next = pc += 4; - ok = decode_legacy(cpu, ctx, insn); + if (!is_prefix_insn(ctx, insn)) { + ok = (decode_insn32(ctx, insn) || + decode_legacy(cpu, ctx, insn)); + } else if ((pc & 63) == 0) { + /* + * Power v3.1, section 1.9 Exceptions: + * attempt to execute a prefixed instruction that crosses a + * 64-byte address boundary (system alignment error). + */ + gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_INSN); + ok = true; + } else { + uint32_t insn2 = translator_ldl_swap(env, pc, need_byteswap(ctx)); + ctx->base.pc_next = pc += 4; + ok = decode_insn64(ctx, deposit64(insn2, 32, 32, insn)); + } if (!ok) { gen_invalid(ctx); } -#if defined(DO_PPC_STATISTICS) - handler->count++; -#endif + /* End the TB when crossing a page boundary. */ + if (ctx->base.is_jmp == DISAS_NEXT && !(pc & ~TARGET_PAGE_MASK)) { + ctx->base.is_jmp = DISAS_TOO_MANY; + } translator_loop_temp_check(&ctx->base); } @@ -9128,7 +8671,7 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } /* else CPU_SINGLE_STEP... */ if (nip <= 0x100 || nip > 0xf00) { - gen_exception(ctx, gen_prep_dbgex(ctx)); + gen_helper_raise_exception(cpu_env, tcg_constant_i32(gen_prep_dbgex(ctx))); return; } } diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc new file mode 100644 index 0000000000..8864ac4516 --- /dev/null +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -0,0 +1,279 @@ +/* + * Power ISA decode for Fixed-Point Facility instructions + * + * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Incorporate CIA into the constant when R=1. + * Validate that when R=1, RA=0. + */ +static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a) +{ + d->rt = a->rt; + d->ra = a->ra; + d->si = a->si; + if (a->r) { + if (unlikely(a->ra != 0)) { + gen_invalid(ctx); + return false; + } + d->si += ctx->cia; + } + return true; +} + +/* + * Fixed-Point Load/Store Instructions + */ + +static bool do_ldst(DisasContext *ctx, int rt, int ra, TCGv displ, bool update, + bool store, MemOp mop) +{ + TCGv ea; + + if (update && (ra == 0 || (!store && ra == rt))) { + gen_invalid(ctx); + return true; + } + gen_set_access_type(ctx, ACCESS_INT); + + ea = tcg_temp_new(); + if (ra) { + tcg_gen_add_tl(ea, cpu_gpr[ra], displ); + } else { + tcg_gen_mov_tl(ea, displ); + } + if (NARROW_MODE(ctx)) { + tcg_gen_ext32u_tl(ea, ea); + } + mop ^= ctx->default_tcg_memop_mask; + if (store) { + tcg_gen_qemu_st_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop); + } else { + tcg_gen_qemu_ld_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop); + } + if (update) { + tcg_gen_mov_tl(cpu_gpr[ra], ea); + } + tcg_temp_free(ea); + + return true; +} + +static bool do_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store, + MemOp mop) +{ + return do_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, store, mop); +} + +static bool do_ldst_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool update, + bool store, MemOp mop) +{ + arg_D d; + if (!resolve_PLS_D(ctx, &d, a)) { + return true; + } + return do_ldst_D(ctx, &d, update, store, mop); +} + +static bool do_ldst_X(DisasContext *ctx, arg_X *a, bool update, + bool store, MemOp mop) +{ + return do_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, mop); +} + +/* Load Byte and Zero */ +TRANS(LBZ, do_ldst_D, false, false, MO_UB) +TRANS(LBZX, do_ldst_X, false, false, MO_UB) +TRANS(LBZU, do_ldst_D, true, false, MO_UB) +TRANS(LBZUX, do_ldst_X, true, false, MO_UB) +TRANS(PLBZ, do_ldst_PLS_D, false, false, MO_UB) + +/* Load Halfword and Zero */ +TRANS(LHZ, do_ldst_D, false, false, MO_UW) +TRANS(LHZX, do_ldst_X, false, false, MO_UW) +TRANS(LHZU, do_ldst_D, true, false, MO_UW) +TRANS(LHZUX, do_ldst_X, true, false, MO_UW) +TRANS(PLHZ, do_ldst_PLS_D, false, false, MO_UW) + +/* Load Halfword Algebraic */ +TRANS(LHA, do_ldst_D, false, false, MO_SW) +TRANS(LHAX, do_ldst_X, false, false, MO_SW) +TRANS(LHAU, do_ldst_D, true, false, MO_SW) +TRANS(LHAXU, do_ldst_X, true, false, MO_SW) +TRANS(PLHA, do_ldst_PLS_D, false, false, MO_SW) + +/* Load Word and Zero */ +TRANS(LWZ, do_ldst_D, false, false, MO_UL) +TRANS(LWZX, do_ldst_X, false, false, MO_UL) +TRANS(LWZU, do_ldst_D, true, false, MO_UL) +TRANS(LWZUX, do_ldst_X, true, false, MO_UL) +TRANS(PLWZ, do_ldst_PLS_D, false, false, MO_UL) + +/* Load Word Algebraic */ +TRANS64(LWA, do_ldst_D, false, false, MO_SL) +TRANS64(LWAX, do_ldst_X, false, false, MO_SL) +TRANS64(LWAUX, do_ldst_X, true, false, MO_SL) +TRANS64(PLWA, do_ldst_PLS_D, false, false, MO_SL) + +/* Load Doubleword */ +TRANS64(LD, do_ldst_D, false, false, MO_Q) +TRANS64(LDX, do_ldst_X, false, false, MO_Q) +TRANS64(LDU, do_ldst_D, true, false, MO_Q) +TRANS64(LDUX, do_ldst_X, true, false, MO_Q) +TRANS64(PLD, do_ldst_PLS_D, false, false, MO_Q) + +/* Store Byte */ +TRANS(STB, do_ldst_D, false, true, MO_UB) +TRANS(STBX, do_ldst_X, false, true, MO_UB) +TRANS(STBU, do_ldst_D, true, true, MO_UB) +TRANS(STBUX, do_ldst_X, true, true, MO_UB) +TRANS(PSTB, do_ldst_PLS_D, false, true, MO_UB) + +/* Store Halfword */ +TRANS(STH, do_ldst_D, false, true, MO_UW) +TRANS(STHX, do_ldst_X, false, true, MO_UW) +TRANS(STHU, do_ldst_D, true, true, MO_UW) +TRANS(STHUX, do_ldst_X, true, true, MO_UW) +TRANS(PSTH, do_ldst_PLS_D, false, true, MO_UW) + +/* Store Word */ +TRANS(STW, do_ldst_D, false, true, MO_UL) +TRANS(STWX, do_ldst_X, false, true, MO_UL) +TRANS(STWU, do_ldst_D, true, true, MO_UL) +TRANS(STWUX, do_ldst_X, true, true, MO_UL) +TRANS(PSTW, do_ldst_PLS_D, false, true, MO_UL) + +/* Store Doubleword */ +TRANS64(STD, do_ldst_D, false, true, MO_Q) +TRANS64(STDX, do_ldst_X, false, true, MO_Q) +TRANS64(STDU, do_ldst_D, true, true, MO_Q) +TRANS64(STDUX, do_ldst_X, true, true, MO_Q) +TRANS64(PSTD, do_ldst_PLS_D, false, true, MO_Q) + +/* + * Fixed-Point Compare Instructions + */ + +static bool do_cmp_X(DisasContext *ctx, arg_X_bfl *a, bool s) +{ + if (a->l) { + REQUIRE_64BIT(ctx); + gen_op_cmp(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf); + } else { + gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf); + } + return true; +} + +static bool do_cmp_D(DisasContext *ctx, arg_D_bf *a, bool s) +{ + if (a->l) { + REQUIRE_64BIT(ctx); + gen_op_cmp(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf); + } else { + gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf); + } + return true; +} + +TRANS(CMP, do_cmp_X, true); +TRANS(CMPL, do_cmp_X, false); +TRANS(CMPI, do_cmp_D, true); +TRANS(CMPLI, do_cmp_D, false); + +/* + * Fixed-Point Arithmetic Instructions + */ + +static bool trans_ADDI(DisasContext *ctx, arg_D *a) +{ + if (a->ra) { + tcg_gen_addi_tl(cpu_gpr[a->rt], cpu_gpr[a->ra], a->si); + } else { + tcg_gen_movi_tl(cpu_gpr[a->rt], a->si); + } + return true; +} + +static bool trans_PADDI(DisasContext *ctx, arg_PLS_D *a) +{ + arg_D d; + if (!resolve_PLS_D(ctx, &d, a)) { + return true; + } + return trans_ADDI(ctx, &d); +} + +static bool trans_ADDIS(DisasContext *ctx, arg_D *a) +{ + a->si <<= 16; + return trans_ADDI(ctx, a); +} + +static bool trans_ADDPCIS(DisasContext *ctx, arg_DX *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + tcg_gen_movi_tl(cpu_gpr[a->rt], ctx->base.pc_next + (a->d << 16)); + return true; +} + +static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a) +{ + gen_invalid(ctx); + return true; +} + +static bool trans_PNOP(DisasContext *ctx, arg_PNOP *a) +{ + return true; +} + +static bool do_set_bool_cond(DisasContext *ctx, arg_X_bi *a, bool neg, bool rev) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + uint32_t mask = 0x08 >> (a->bi & 0x03); + TCGCond cond = rev ? TCG_COND_EQ : TCG_COND_NE; + TCGv temp = tcg_temp_new(); + + tcg_gen_extu_i32_tl(temp, cpu_crf[a->bi >> 2]); + tcg_gen_andi_tl(temp, temp, mask); + tcg_gen_setcondi_tl(cond, cpu_gpr[a->rt], temp, 0); + if (neg) { + tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->rt]); + } + tcg_temp_free(temp); + + return true; +} + +TRANS(SETBC, do_set_bool_cond, false, false) +TRANS(SETBCR, do_set_bool_cond, false, true) +TRANS(SETNBC, do_set_bool_cond, true, false) +TRANS(SETNBCR, do_set_bool_cond, true, true) + +static bool trans_CFUGED(DisasContext *ctx, arg_X *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA310); +#if defined(TARGET_PPC64) + gen_helper_cfuged(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} diff --git a/target/ppc/translate/vector-impl.c.inc b/target/ppc/translate/vector-impl.c.inc new file mode 100644 index 0000000000..117ce9b137 --- /dev/null +++ b/target/ppc/translate/vector-impl.c.inc @@ -0,0 +1,56 @@ +/* + * Power ISA decode for Vector Facility instructions + * + * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#define REQUIRE_ALTIVEC(CTX) \ + do { \ + if (unlikely(!(CTX)->altivec_enabled)) { \ + gen_exception((CTX), POWERPC_EXCP_VPU); \ + return true; \ + } \ + } while (0) + +static bool trans_VCFUGED(DisasContext *ctx, arg_VX *a) +{ + TCGv_i64 tgt, src, mask; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_ALTIVEC(ctx); + + tgt = tcg_temp_new_i64(); + src = tcg_temp_new_i64(); + mask = tcg_temp_new_i64(); + + /* centrifuge lower double word */ + get_cpu_vsrl(src, a->vra + 32); + get_cpu_vsrl(mask, a->vrb + 32); + gen_helper_cfuged(tgt, src, mask); + set_cpu_vsrl(a->vrt + 32, tgt); + + /* centrifuge higher double word */ + get_cpu_vsrh(src, a->vra + 32); + get_cpu_vsrh(mask, a->vrb + 32); + gen_helper_cfuged(tgt, src, mask); + set_cpu_vsrh(a->vrt + 32, tgt); + + tcg_temp_free_i64(tgt); + tcg_temp_free_i64(src); + tcg_temp_free_i64(mask); + + return true; +} |