aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-06-03 10:00:35 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-06-03 10:00:35 +0100
commita97978bcc2d1f650c7d411428806e5b03082b8c7 (patch)
tree29f81b0392e3b87dfa81c5ef10849225307d60bc
parent8e6dad2028d01b7f9ec76cf3b83457fab57fa1eb (diff)
parenteba3c766fe355a4e593c1ee6944770f80b68acad (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>
-rw-r--r--docs/system/removed-features.rst5
-rw-r--r--hmp-commands-info.hx13
-rw-r--r--hw/core/cpu-common.c9
-rw-r--r--hw/ppc/pef.c6
-rw-r--r--hw/ppc/spapr.c8
-rw-r--r--hw/ppc/spapr_nvdimm.c16
-rw-r--r--hw/ppc/spapr_pci_vfio.c40
-rw-r--r--hw/ppc/spapr_rtas.c15
-rw-r--r--include/hw/core/cpu.h12
-rw-r--r--include/hw/ppc/spapr.h3
-rw-r--r--include/hw/ppc/spapr_nvdimm.h14
-rw-r--r--monitor/misc.c11
-rw-r--r--target/ppc/cpu.c68
-rw-r--r--target/ppc/cpu.h15
-rw-r--r--target/ppc/cpu_init.c216
-rw-r--r--target/ppc/excp_helper.c119
-rw-r--r--target/ppc/fpu_helper.c246
-rw-r--r--target/ppc/gdbstub.c7
-rw-r--r--target/ppc/helper.h1
-rw-r--r--target/ppc/insn32.decode126
-rw-r--r--target/ppc/insn64.decode124
-rw-r--r--target/ppc/int_helper.c62
-rw-r--r--target/ppc/internal.h2
-rw-r--r--target/ppc/meson.build20
-rw-r--r--target/ppc/misc_helper.c40
-rw-r--r--target/ppc/mmu-hash32.c1
-rw-r--r--target/ppc/mmu-hash64.c11
-rw-r--r--target/ppc/mmu-radix64.c1
-rw-r--r--target/ppc/mmu_helper.c44
-rw-r--r--target/ppc/tcg-stub.c45
-rw-r--r--target/ppc/translate.c637
-rw-r--r--target/ppc/translate/fixedpoint-impl.c.inc279
-rw-r--r--target/ppc/translate/vector-impl.c.inc56
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;
+}