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:
Peter Maydell 2021-06-03 10:00:35 +01:00
commit a97978bcc2
33 changed files with 1062 additions and 1206 deletions

View File

@ -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
-------------------

View File

@ -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",

View File

@ -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));

View File

@ -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)

View File

@ -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)

View File

@ -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)));

View File

@ -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;
}

View File

@ -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

View File

@ -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:

View File

@ -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;

View File

@ -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);

View File

@ -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");

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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; \
} \
\

View File

@ -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;

View File

@ -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)

126
target/ppc/insn32.decode Normal file
View File

@ -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

124
target/ppc/insn64.decode Normal file
View File

@ -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
}

View File

@ -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)

View File

@ -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);

View File

@ -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',

View File

@ -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

View File

@ -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"

View File

@ -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)
{

View File

@ -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"

View File

@ -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 */
/*****************************************************************************/

45
target/ppc/tcg-stub.c Normal file
View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}