mirror of https://github.com/xemu-project/xemu.git
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. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAmC4kOsACgkQbDjKyiDZ s5Lmfw/+Pq8EWAUWCi1jED/DzmtCAMGbBD7npWjY/kJR1WluSsvhgJBPXTXKDQmv x4TDYd2lZueTU7YRXN6bLGKzeJos/6U8FNb4CK6uaL0syc7OsvgNY0lJNUDG/Ght IcFjLqMAWjImCKGLPIqyOmfPWFv1UU4MiG3bf2gYr4cbunxWHGs0wF+32fcXL/KR Q4FRKUJuh5a5OjJBkodWsnVm263fSFuKSb3Z2SDSV7Wpk9306rEsDrpcPl81xrTk pgZ06iY7pDNVVVzRhonfldbpXCwJdENUMPbZJJQ/9kf0qtfuLE4WlVqAtcuAuXZm ise/6V/GQ0yTTMDuTQxBFOGRoEb/sG+NLAwiaEcPH9denWyhFX8RHK/uKCCxlmcH arzF2ar6i9PGKFUAnzoH7n5+GQGDOBsFbOmAvSPe0KGuDWYQGKGwT+YifCyGIqnB 7NV2n3y0kqEPlCHN1esjSMohgfKxrrI50WZQAo3XJRp6Z7d7643SrA/CXOVmwnvY MbUuHoOQa4kA02v8SAiaC2XZ0iXh1OMq4vxNb7jiNgdlGhfsjUi6IarTwnOikF1Y 2cdxc62WTpIdHkSfoEEI1doP51FfD7vjBVrUOEh7K0D1DAVsrbO6SkPiWpMljXN6 QeJLpcZ/4eJR/MN2tndt79GgwrYx2dboD2h8RfzGXsazy1gb8jk= =4ZDC -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
a97978bcc2
|
@ -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
|
||||
-------------------
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
@ -362,27 +352,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
|||
excp = powerpc_reset_wakeup(cs, env, excp, &msr);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -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
|
||||
|
|
|
@ -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; \
|
||||
} \
|
||||
\
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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,84 +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, \
|
||||
.opc2 = op2, \
|
||||
.opc3 = op3, \
|
||||
.opc4 = 0xff, \
|
||||
.handler = { \
|
||||
.inval1 = invl, \
|
||||
.type = _typ, \
|
||||
.type2 = _typ2, \
|
||||
.handler = &gen_##name, \
|
||||
.oname = stringify(name), \
|
||||
}, \
|
||||
.oname = stringify(name), \
|
||||
}
|
||||
#define GEN_OPCODE_DUAL(name, op1, op2, op3, invl1, invl2, _typ, _typ2) \
|
||||
{ \
|
||||
.opc1 = op1, \
|
||||
.opc2 = op2, \
|
||||
.opc3 = op3, \
|
||||
.opc4 = 0xff, \
|
||||
.handler = { \
|
||||
.inval1 = invl1, \
|
||||
.inval2 = invl2, \
|
||||
.type = _typ, \
|
||||
.type2 = _typ2, \
|
||||
.handler = &gen_##name, \
|
||||
.oname = stringify(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, \
|
||||
}, \
|
||||
.oname = onam, \
|
||||
}
|
||||
#define GEN_OPCODE3(name, op1, op2, op3, op4, invl, _typ, _typ2) \
|
||||
{ \
|
||||
.opc1 = op1, \
|
||||
.opc2 = op2, \
|
||||
.opc3 = op3, \
|
||||
.opc4 = op4, \
|
||||
.handler = { \
|
||||
.inval1 = invl, \
|
||||
.type = _typ, \
|
||||
.type2 = _typ2, \
|
||||
.handler = &gen_##name, \
|
||||
.oname = stringify(name), \
|
||||
}, \
|
||||
.oname = stringify(name), \
|
||||
}
|
||||
#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, \
|
||||
}, \
|
||||
.oname = onam, \
|
||||
}
|
||||
#else
|
||||
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2) \
|
||||
{ \
|
||||
.opc1 = op1, \
|
||||
|
@ -1494,7 +1409,6 @@ typedef struct opcode_t {
|
|||
}, \
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue