aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2022-07-07 06:21:05 +0530
committerRichard Henderson <richard.henderson@linaro.org>2022-07-07 06:21:05 +0530
commit8e9398e3b1a860b8c29c670c1b6c36afe8d87849 (patch)
tree7f7e081e7cebdc04955398b711eb8fb5d2640574
parent0e3723005bfea2f70157bf951f3e6be03bbf6e74 (diff)
parent0b83377f46042529adbbf3a77f7ffb6f1e8a0aaa (diff)
downloadqemu-8e9398e3b1a860b8c29c670c1b6c36afe8d87849.zip
qemu-8e9398e3b1a860b8c29c670c1b6c36afe8d87849.tar.gz
qemu-8e9398e3b1a860b8c29c670c1b6c36afe8d87849.tar.bz2
Merge tag 'pull-ppc-20220706' of https://gitlab.com/danielhb/qemu into staging
ppc patch queue for 2022-07-06: This queue consists of improvements and bug fixes in TCG, powernv and pSeries, with some fixes in other areas as well. - tcg and target/ppc: BCDA and mffscdrn implementations, Remove CONFIG_INT128 conditional code - fix '-cpu max' alias - remove '-cpu default' alias - spapr: fixes in DDW handling, H_WATCHDOG support - powernv: cleanups in the pnv-phb3/4 models - fix core type of MPC8555 and MPC8560 models # -----BEGIN PGP SIGNATURE----- # # iHUEABYKAB0WIQQX6/+ZI9AYAK8oOBk82cqW3gMxZAUCYsXrpgAKCRA82cqW3gMx # ZBe9AP4oqMTFw7r9EQPJU4QFMUeAVABl4o0xNb2wLyYov9CtKAD+LoVERSmtLTJ1 # kFpgBrRTWKVylaLEdZQoTdFlJeBwzQg= # =GPG1 # -----END PGP SIGNATURE----- # gpg: Signature made Thu 07 Jul 2022 01:38:06 AM +0530 # gpg: using EDDSA key 17EBFF9923D01800AF2838193CD9CA96DE033164 # gpg: Good signature from "Daniel Henrique Barboza <danielhb413@gmail.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 17EB FF99 23D0 1800 AF28 3819 3CD9 CA96 DE03 3164 * tag 'pull-ppc-20220706' of https://gitlab.com/danielhb/qemu: (34 commits) target/ppc: Fix MPC8555 and MPC8560 core type to e500v1 target/ppc/cpu-models: Remove the "default" CPU alias target/ppc: Return default CPU for max CPU target/ppc: implement cdtbcd target/ppc: implement cbcdtd target/ppc: implement addg6s target/ppc: Add flag for ISA v2.06 BCDA instructions tests/tcg/ppc64: Add mffsce test target/ppc: Implement mffscdrn[i] instructions target/ppc: Move mffs[.] to decodetree target/ppc: Move mffsl to decodetree target/ppc: Move mffsce to decodetree target/ppc: Move mffscrn[i] to decodetree target/ppc: Fix insn32.decode style issues ppc/spapr: Implement H_WATCHDOG ppc: Define SETFIELD for the ppc target target/ppc: use int128.h methods in vsubcuq target/ppc: use int128.h methods in vsubecuq and vsubeuqm target/ppc: use int128.h methods in vsubuqm target/ppc: use int128.h methods in vaddcuq ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r--hw/intc/pnv_xive.c20
-rw-r--r--hw/intc/pnv_xive2.c20
-rw-r--r--hw/pci-host/pnv_phb3.c22
-rw-r--r--hw/pci-host/pnv_phb4.c40
-rw-r--r--hw/pci-host/pnv_phb4_pec.c3
-rw-r--r--hw/ppc/pnv.c102
-rw-r--r--hw/ppc/spapr.c4
-rw-r--r--hw/ppc/spapr_iommu.c3
-rw-r--r--hw/ppc/spapr_pci.c6
-rw-r--r--hw/ppc/spapr_rtas_ddw.c34
-rw-r--r--hw/watchdog/meson.build1
-rw-r--r--hw/watchdog/spapr_watchdog.c274
-rw-r--r--hw/watchdog/trace-events7
-rw-r--r--include/hw/pci-host/pnv_phb3_regs.h16
-rw-r--r--include/hw/ppc/pnv.h3
-rw-r--r--include/hw/ppc/spapr.h26
-rw-r--r--target/ppc/cpu-models.c17
-rw-r--r--target/ppc/cpu-models.h14
-rw-r--r--target/ppc/cpu.h89
-rw-r--r--target/ppc/cpu_init.c29
-rw-r--r--target/ppc/dfp_helper.c65
-rw-r--r--target/ppc/helper.h20
-rw-r--r--target/ppc/insn32.decode71
-rw-r--r--target/ppc/int_helper.c229
-rw-r--r--target/ppc/internal.h3
-rw-r--r--target/ppc/translate/fixedpoint-impl.c.inc51
-rw-r--r--target/ppc/translate/fp-impl.c.inc203
-rw-r--r--target/ppc/translate/fp-ops.c.inc9
-rw-r--r--target/ppc/translate/vmx-impl.c.inc32
-rw-r--r--target/ppc/translate/vmx-ops.c.inc9
-rw-r--r--tests/tcg/ppc64/Makefile.target1
-rw-r--r--tests/tcg/ppc64le/Makefile.target1
-rw-r--r--tests/tcg/ppc64le/mffsce.c37
33 files changed, 885 insertions, 576 deletions
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
index 1ce1d7b..c7b75ed 100644
--- a/hw/intc/pnv_xive.c
+++ b/hw/intc/pnv_xive.c
@@ -67,26 +67,6 @@ static const XiveVstInfo vst_infos[] = {
(xive)->chip->chip_id, ## __VA_ARGS__);
/*
- * QEMU version of the GETFIELD/SETFIELD macros
- *
- * TODO: It might be better to use the existing extract64() and
- * deposit64() but this means that all the register definitions will
- * change and become incompatible with the ones found in skiboot.
- *
- * Keep it as it is for now until we find a common ground.
- */
-static inline uint64_t GETFIELD(uint64_t mask, uint64_t word)
-{
- return (word & mask) >> ctz64(mask);
-}
-
-static inline uint64_t SETFIELD(uint64_t mask, uint64_t word,
- uint64_t value)
-{
- return (word & ~mask) | ((value << ctz64(mask)) & mask);
-}
-
-/*
* When PC_TCTXT_CHIPID_OVERRIDE is configured, the PC_TCTXT_CHIPID
* field overrides the hardwired chip ID in the Powerbus operations
* and for CAM compares
diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c
index f31c53c..f22ce5c 100644
--- a/hw/intc/pnv_xive2.c
+++ b/hw/intc/pnv_xive2.c
@@ -76,26 +76,6 @@ static const XiveVstInfo vst_infos[] = {
(xive)->chip->chip_id, ## __VA_ARGS__);
/*
- * QEMU version of the GETFIELD/SETFIELD macros
- *
- * TODO: It might be better to use the existing extract64() and
- * deposit64() but this means that all the register definitions will
- * change and become incompatible with the ones found in skiboot.
- *
- * Keep it as it is for now until we find a common ground.
- */
-static inline uint64_t GETFIELD(uint64_t mask, uint64_t word)
-{
- return (word & mask) >> ctz64(mask);
-}
-
-static inline uint64_t SETFIELD(uint64_t mask, uint64_t word,
- uint64_t value)
-{
- return (word & ~mask) | ((value << ctz64(mask)) & mask);
-}
-
-/*
* TODO: Document block id override
*/
static uint32_t pnv_xive2_block_id(PnvXive2 *xive)
diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c
index 26ac9b7..d58d3c1 100644
--- a/hw/pci-host/pnv_phb3.c
+++ b/hw/pci-host/pnv_phb3.c
@@ -1052,7 +1052,8 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp)
pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb);
- pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb), TYPE_PNV_PHB3_ROOT_PORT);
+ pnv_phb_attach_root_port(pci, TYPE_PNV_PHB3_ROOT_PORT,
+ phb->phb_id, phb->chip_id);
}
void pnv_phb3_update_regions(PnvPHB3 *phb)
@@ -1129,33 +1130,14 @@ static const TypeInfo pnv_phb3_root_bus_info = {
.name = TYPE_PNV_PHB3_ROOT_BUS,
.parent = TYPE_PCIE_BUS,
.class_init = pnv_phb3_root_bus_class_init,
- .interfaces = (InterfaceInfo[]) {
- { INTERFACE_PCIE_DEVICE },
- { }
- },
};
static void pnv_phb3_root_port_realize(DeviceState *dev, Error **errp)
{
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
PCIDevice *pci = PCI_DEVICE(dev);
- PCIBus *bus = pci_get_bus(pci);
- PnvPHB3 *phb = NULL;
Error *local_err = NULL;
- phb = (PnvPHB3 *) object_dynamic_cast(OBJECT(bus->qbus.parent),
- TYPE_PNV_PHB3);
-
- if (!phb) {
- error_setg(errp,
-"pnv_phb3_root_port devices must be connected to pnv-phb3 buses");
- return;
- }
-
- /* Set unique chassis/slot values for the root port */
- qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
- qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);
-
rpc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 6594016..67ddde4 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -31,22 +31,6 @@
qemu_log_mask(LOG_GUEST_ERROR, "phb4_pec[%d:%d]: " fmt "\n", \
(pec)->chip_id, (pec)->index, ## __VA_ARGS__)
-/*
- * QEMU version of the GETFIELD/SETFIELD macros
- *
- * These are common with the PnvXive model.
- */
-static inline uint64_t GETFIELD(uint64_t mask, uint64_t word)
-{
- return (word & mask) >> ctz64(mask);
-}
-
-static inline uint64_t SETFIELD(uint64_t mask, uint64_t word,
- uint64_t value)
-{
- return (word & ~mask) | ((value << ctz64(mask)) & mask);
-}
-
static PCIDevice *pnv_phb4_find_cfg_dev(PnvPHB4 *phb)
{
PCIHostState *pci = PCI_HOST_BRIDGE(phb);
@@ -1547,6 +1531,7 @@ static void pnv_phb4_instance_init(Object *obj)
static void pnv_phb4_realize(DeviceState *dev, Error **errp)
{
PnvPHB4 *phb = PNV_PHB4(dev);
+ PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(phb->pec);
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
XiveSource *xsrc = &phb->xsrc;
int nr_irqs;
@@ -1583,6 +1568,10 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
pci_setup_iommu(pci->bus, pnv_phb4_dma_iommu, phb);
pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
+ /* Add a single Root port if running with defaults */
+ pnv_phb_attach_root_port(pci, pecc->rp_model,
+ phb->phb_id, phb->chip_id);
+
/* Setup XIVE Source */
if (phb->big_phb) {
nr_irqs = PNV_PHB4_MAX_INTs;
@@ -1747,10 +1736,6 @@ static const TypeInfo pnv_phb4_root_bus_info = {
.name = TYPE_PNV_PHB4_ROOT_BUS,
.parent = TYPE_PCIE_BUS,
.class_init = pnv_phb4_root_bus_class_init,
- .interfaces = (InterfaceInfo[]) {
- { INTERFACE_PCIE_DEVICE },
- { }
- },
};
static void pnv_phb4_root_port_reset(DeviceState *dev)
@@ -1777,23 +1762,8 @@ static void pnv_phb4_root_port_reset(DeviceState *dev)
static void pnv_phb4_root_port_realize(DeviceState *dev, Error **errp)
{
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
- PCIDevice *pci = PCI_DEVICE(dev);
- PCIBus *bus = pci_get_bus(pci);
- PnvPHB4 *phb = NULL;
Error *local_err = NULL;
- phb = (PnvPHB4 *) object_dynamic_cast(OBJECT(bus->qbus.parent),
- TYPE_PNV_PHB4);
-
- if (!phb) {
- error_setg(errp, "%s must be connected to pnv-phb4 buses", dev->id);
- return;
- }
-
- /* Set unique chassis/slot values for the root port */
- qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
- qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);
-
rpc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c
index 8b7e823..c9aaf1c 100644
--- a/hw/pci-host/pnv_phb4_pec.c
+++ b/hw/pci-host/pnv_phb4_pec.c
@@ -130,9 +130,6 @@ static void pnv_pec_default_phb_realize(PnvPhb4PecState *pec,
if (!sysbus_realize(SYS_BUS_DEVICE(phb), errp)) {
return;
}
-
- /* Add a single Root port if running with defaults */
- pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb), pecc->rp_model);
}
static void pnv_pec_realize(DeviceState *dev, Error **errp)
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 7c08a78..d3f77c8 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -652,25 +652,19 @@ static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
}
-static int pnv_chip_power8_pic_print_info_child(Object *child, void *opaque)
-{
- Monitor *mon = opaque;
- PnvPHB3 *phb3 = (PnvPHB3 *) object_dynamic_cast(child, TYPE_PNV_PHB3);
-
- if (phb3) {
- pnv_phb3_msi_pic_print_info(&phb3->msis, mon);
- ics_pic_print_info(&phb3->lsis, mon);
- }
- return 0;
-}
-
static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon)
{
Pnv8Chip *chip8 = PNV8_CHIP(chip);
+ int i;
ics_pic_print_info(&chip8->psi.ics, mon);
- object_child_foreach(OBJECT(chip),
- pnv_chip_power8_pic_print_info_child, mon);
+
+ for (i = 0; i < chip8->num_phbs; i++) {
+ PnvPHB3 *phb3 = &chip8->phbs[i];
+
+ pnv_phb3_msi_pic_print_info(&phb3->msis, mon);
+ ics_pic_print_info(&phb3->lsis, mon);
+ }
}
static int pnv_chip_power9_pic_print_info_child(Object *child, void *opaque)
@@ -1189,10 +1183,26 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
}
}
-/* Attach a root port device */
-void pnv_phb_attach_root_port(PCIHostState *pci, const char *name)
+/*
+ * Attach a root port device.
+ *
+ * 'index' will be used both as a PCIE slot value and to calculate
+ * QOM id. 'chip_id' is going to be used as PCIE chassis for the
+ * root port.
+ */
+void pnv_phb_attach_root_port(PCIHostState *pci, const char *name,
+ int index, int chip_id)
{
PCIDevice *root = pci_new(PCI_DEVFN(0, 0), name);
+ g_autofree char *default_id = g_strdup_printf("%s[%d]", name, index);
+ const char *dev_id = DEVICE(root)->id;
+
+ object_property_add_child(OBJECT(pci->bus), dev_id ? dev_id : default_id,
+ OBJECT(root));
+
+ /* Set unique chassis/slot values for the root port */
+ qdev_prop_set_uint8(DEVICE(root), "chassis", chip_id);
+ qdev_prop_set_uint16(DEVICE(root), "slot", index);
pci_realize_and_unref(root, pci->bus, &error_fatal);
}
@@ -1934,44 +1944,28 @@ PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir)
return NULL;
}
-typedef struct ForeachPhb3Args {
- int irq;
- ICSState *ics;
-} ForeachPhb3Args;
-
-static int pnv_ics_get_child(Object *child, void *opaque)
-{
- ForeachPhb3Args *args = opaque;
- PnvPHB3 *phb3 = (PnvPHB3 *) object_dynamic_cast(child, TYPE_PNV_PHB3);
-
- if (phb3) {
- if (ics_valid_irq(&phb3->lsis, args->irq)) {
- args->ics = &phb3->lsis;
- }
- if (ics_valid_irq(ICS(&phb3->msis), args->irq)) {
- args->ics = ICS(&phb3->msis);
- }
- }
- return args->ics ? 1 : 0;
-}
-
static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
{
PnvMachineState *pnv = PNV_MACHINE(xi);
- ForeachPhb3Args args = { irq, NULL };
- int i;
+ int i, j;
for (i = 0; i < pnv->num_chips; i++) {
- PnvChip *chip = pnv->chips[i];
Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
if (ics_valid_irq(&chip8->psi.ics, irq)) {
return &chip8->psi.ics;
}
- object_child_foreach(OBJECT(chip), pnv_ics_get_child, &args);
- if (args.ics) {
- return args.ics;
+ for (j = 0; j < chip8->num_phbs; j++) {
+ PnvPHB3 *phb3 = &chip8->phbs[j];
+
+ if (ics_valid_irq(&phb3->lsis, irq)) {
+ return &phb3->lsis;
+ }
+
+ if (ics_valid_irq(ICS(&phb3->msis), irq)) {
+ return ICS(&phb3->msis);
+ }
}
}
return NULL;
@@ -1990,28 +1984,22 @@ PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id)
return NULL;
}
-static int pnv_ics_resend_child(Object *child, void *opaque)
-{
- PnvPHB3 *phb3 = (PnvPHB3 *) object_dynamic_cast(child, TYPE_PNV_PHB3);
-
- if (phb3) {
- ics_resend(&phb3->lsis);
- ics_resend(ICS(&phb3->msis));
- }
- return 0;
-}
-
static void pnv_ics_resend(XICSFabric *xi)
{
PnvMachineState *pnv = PNV_MACHINE(xi);
- int i;
+ int i, j;
for (i = 0; i < pnv->num_chips; i++) {
- PnvChip *chip = pnv->chips[i];
Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
ics_resend(&chip8->psi.ics);
- object_child_foreach(OBJECT(chip), pnv_ics_resend_child, NULL);
+
+ for (j = 0; j < chip8->num_phbs; j++) {
+ PnvPHB3 *phb3 = &chip8->phbs[j];
+
+ ics_resend(&phb3->lsis);
+ ics_resend(ICS(&phb3->msis));
+ }
}
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index fd4942e..9a5382d 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -898,6 +898,8 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
add_str(hypertas, "hcall-hpt-resize");
}
+ add_str(hypertas, "hcall-watchdog");
+
_FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions",
hypertas->str, hypertas->len));
g_string_free(hypertas, TRUE);
@@ -3051,6 +3053,8 @@ static void spapr_machine_init(MachineState *machine)
spapr->vof->fw_size = fw_size; /* for claim() on itself */
spapr_register_hypercall(KVMPPC_H_VOF_CLIENT, spapr_h_vof_client);
}
+
+ spapr_watchdog_init(spapr);
}
#define DEFAULT_KVM_TYPE "auto"
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 81e5a1a..63e34d4 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -279,7 +279,7 @@ static const VMStateDescription vmstate_spapr_tce_table_ex = {
static const VMStateDescription vmstate_spapr_tce_table = {
.name = "spapr_iommu",
- .version_id = 2,
+ .version_id = 3,
.minimum_version_id = 2,
.pre_save = spapr_tce_table_pre_save,
.post_load = spapr_tce_table_post_load,
@@ -292,6 +292,7 @@ static const VMStateDescription vmstate_spapr_tce_table = {
VMSTATE_BOOL(bypass, SpaprTceTable),
VMSTATE_VARRAY_UINT32_ALLOC(mig_table, SpaprTceTable, mig_nb_table, 0,
vmstate_info_uint64, uint64_t),
+ VMSTATE_BOOL_V(def_win, SpaprTceTable, 3),
VMSTATE_END_OF_LIST()
},
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index b2f5fbe..67e9d46 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -2067,6 +2067,7 @@ void spapr_phb_dma_reset(SpaprPhbState *sphb)
tcet = spapr_tce_find_by_liobn(sphb->dma_liobn[0]);
spapr_tce_table_enable(tcet, SPAPR_TCE_PAGE_SHIFT, sphb->dma_win_addr,
sphb->dma_win_size >> SPAPR_TCE_PAGE_SHIFT);
+ tcet->def_win = true;
}
static void spapr_phb_reset(DeviceState *qdev)
@@ -2359,8 +2360,9 @@ int spapr_dt_phb(SpaprMachineState *spapr, SpaprPhbState *phb,
cpu_to_be32(RTAS_IBM_REMOVE_PE_DMA_WINDOW)
};
uint32_t ddw_extensions[] = {
- cpu_to_be32(1),
- cpu_to_be32(RTAS_IBM_RESET_PE_DMA_WINDOW)
+ cpu_to_be32(2),
+ cpu_to_be32(RTAS_IBM_RESET_PE_DMA_WINDOW),
+ cpu_to_be32(1), /* 1: ibm,query-pe-dma-window 6 outputs, PAPR 2.8 */
};
SpaprTceTable *tcet;
SpaprDrc *drc;
diff --git a/hw/ppc/spapr_rtas_ddw.c b/hw/ppc/spapr_rtas_ddw.c
index 13d339c..7ba1138 100644
--- a/hw/ppc/spapr_rtas_ddw.c
+++ b/hw/ppc/spapr_rtas_ddw.c
@@ -100,7 +100,7 @@ static void rtas_ibm_query_pe_dma_window(PowerPCCPU *cpu,
uint64_t buid;
uint32_t avail, addr, pgmask = 0;
- if ((nargs != 3) || (nret != 5)) {
+ if ((nargs != 3) || ((nret != 5) && (nret != 6))) {
goto param_error_exit;
}
@@ -118,9 +118,20 @@ static void rtas_ibm_query_pe_dma_window(PowerPCCPU *cpu,
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
rtas_st(rets, 1, avail);
- rtas_st(rets, 2, 0x80000000); /* The largest window we can possibly have */
- rtas_st(rets, 3, pgmask);
- rtas_st(rets, 4, 0); /* DMA migration mask, not supported */
+ if (nret == 6) {
+ /*
+ * Set the Max TCE number as 1<<(58-21) = 0x20.0000.0000
+ * 1<<59 is the huge window start and 21 is 2M page shift.
+ */
+ rtas_st(rets, 2, 0x00000020);
+ rtas_st(rets, 3, 0x00000000);
+ rtas_st(rets, 4, pgmask);
+ rtas_st(rets, 5, 0); /* DMA migration mask, not supported */
+ } else {
+ rtas_st(rets, 2, 0x80000000);
+ rtas_st(rets, 3, pgmask);
+ rtas_st(rets, 4, 0); /* DMA migration mask, not supported */
+ }
trace_spapr_iommu_ddw_query(buid, addr, avail, 0x80000000, pgmask);
return;
@@ -215,6 +226,7 @@ static void rtas_ibm_remove_pe_dma_window(PowerPCCPU *cpu,
SpaprPhbState *sphb;
SpaprTceTable *tcet;
uint32_t liobn;
+ bool def_win_removed;
if ((nargs != 1) || (nret != 1)) {
goto param_error_exit;
@@ -231,9 +243,23 @@ static void rtas_ibm_remove_pe_dma_window(PowerPCCPU *cpu,
goto param_error_exit;
}
+ def_win_removed = tcet->def_win;
spapr_tce_table_disable(tcet);
trace_spapr_iommu_ddw_remove(liobn);
+ /*
+ * PAPR+/LoPAPR says:
+ * The platform must restore the default DMA window for the PE on a call
+ * to the ibm,remove-pe-dma-window RTAS call when all of the following
+ * are true:
+ * a. The call removes the last DMA window remaining for the PE.
+ * b. The DMA window being removed is not the default window
+ */
+ if (spapr_phb_get_active_win_num(sphb) == 0 && !def_win_removed) {
+ spapr_phb_dma_reset(sphb);
+ trace_spapr_iommu_ddw_reset(sphb->buid, 0);
+ }
+
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
return;
diff --git a/hw/watchdog/meson.build b/hw/watchdog/meson.build
index 054c403..8974b5c 100644
--- a/hw/watchdog/meson.build
+++ b/hw/watchdog/meson.build
@@ -6,3 +6,4 @@ softmmu_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c'))
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c'))
softmmu_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c'))
softmmu_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c'))
+specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_watchdog.c'))
diff --git a/hw/watchdog/spapr_watchdog.c b/hw/watchdog/spapr_watchdog.c
new file mode 100644
index 0000000..55ff1f0
--- /dev/null
+++ b/hw/watchdog/spapr_watchdog.c
@@ -0,0 +1,274 @@
+/*
+ * 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 "qapi/error.h"
+#include "target/ppc/cpu.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+#include "hw/ppc/spapr.h"
+
+#define FIELD_BE(reg, field, start, len) \
+ FIELD(reg, field, 64 - (start + len), len)
+
+/*
+ * Bits 47: "leaveOtherWatchdogsRunningOnTimeout", specified on
+ * the "Start watchdog" operation,
+ * 0 - stop out-standing watchdogs on timeout,
+ * 1 - leave outstanding watchdogs running on timeout
+ */
+FIELD_BE(PSERIES_WDTF, LEAVE_OTHER, 47, 1)
+
+/* Bits 48-55: "operation" */
+FIELD_BE(PSERIES_WDTF, OP, 48, 8)
+#define PSERIES_WDTF_OP_START 0x1
+#define PSERIES_WDTF_OP_STOP 0x2
+#define PSERIES_WDTF_OP_QUERY 0x3
+#define PSERIES_WDTF_OP_QUERY_LPM 0x4
+
+/* Bits 56-63: "timeoutAction" */
+FIELD_BE(PSERIES_WDTF, ACTION, 56, 8)
+#define PSERIES_WDTF_ACTION_HARD_POWER_OFF 0x1
+#define PSERIES_WDTF_ACTION_HARD_RESTART 0x2
+#define PSERIES_WDTF_ACTION_DUMP_RESTART 0x3
+
+FIELD_BE(PSERIES_WDTF, RESERVED, 0, 47)
+
+/* Special watchdogNumber for the "stop all watchdogs" operation */
+#define PSERIES_WDT_STOP_ALL ((uint64_t)~0)
+
+/*
+ * For the "Query watchdog capabilities" operation, a uint64 structure
+ * defined as:
+ * Bits 0-15: The minimum supported timeout in milliseconds
+ * Bits 16-31: The number of watchdogs supported
+ * Bits 32-63: Reserved
+ */
+FIELD_BE(PSERIES_WDTQ, MIN_TIMEOUT, 0, 16)
+FIELD_BE(PSERIES_WDTQ, NUM, 16, 16)
+
+/*
+ * For the "Query watchdog LPM requirement" operation:
+ * 1 = The given "watchdogNumber" must be stopped prior to suspending
+ * 2 = The given "watchdogNumber" does not have to be stopped prior to
+ * suspending
+ */
+#define PSERIES_WDTQL_STOPPED 1
+#define PSERIES_WDTQL_QUERY_NOT_STOPPED 2
+
+#define WDT_MIN_TIMEOUT 1 /* 1ms */
+
+static target_ulong watchdog_stop(unsigned watchdogNumber, SpaprWatchdog *w)
+{
+ target_ulong ret = H_NOOP;
+
+ if (timer_pending(&w->timer)) {
+ timer_del(&w->timer);
+ ret = H_SUCCESS;
+ }
+ trace_spapr_watchdog_stop(watchdogNumber, ret);
+
+ return ret;
+}
+
+static target_ulong watchdog_stop_all(SpaprMachineState *spapr)
+{
+ target_ulong ret = H_NOOP;
+ int i;
+
+ for (i = 1; i <= ARRAY_SIZE(spapr->wds); ++i) {
+ target_ulong r = watchdog_stop(i, &spapr->wds[i - 1]);
+
+ if (r != H_NOOP && r != H_SUCCESS) {
+ ret = r;
+ }
+ }
+
+ return ret;
+}
+
+static void watchdog_expired(void *pw)
+{
+ SpaprWatchdog *w = pw;
+ CPUState *cs;
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ unsigned num = w - spapr->wds;
+
+ g_assert(num < ARRAY_SIZE(spapr->wds));
+ trace_spapr_watchdog_expired(num, w->action);
+ switch (w->action) {
+ case PSERIES_WDTF_ACTION_HARD_POWER_OFF:
+ qemu_system_vmstop_request(RUN_STATE_SHUTDOWN);
+ break;
+ case PSERIES_WDTF_ACTION_HARD_RESTART:
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ break;
+ case PSERIES_WDTF_ACTION_DUMP_RESTART:
+ CPU_FOREACH(cs) {
+ async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
+ }
+ break;
+ }
+ if (!w->leave_others) {
+ watchdog_stop_all(spapr);
+ }
+}
+
+static target_ulong h_watchdog(PowerPCCPU *cpu,
+ SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong ret = H_SUCCESS;
+ target_ulong flags = args[0];
+ target_ulong watchdogNumber = args[1]; /* 1-Based per PAPR */
+ target_ulong timeoutInMs = args[2];
+ unsigned operation = FIELD_EX64(flags, PSERIES_WDTF, OP);
+ unsigned timeoutAction = FIELD_EX64(flags, PSERIES_WDTF, ACTION);
+ SpaprWatchdog *w;
+
+ if (FIELD_EX64(flags, PSERIES_WDTF, RESERVED)) {
+ return H_PARAMETER;
+ }
+
+ switch (operation) {
+ case PSERIES_WDTF_OP_START:
+ if (watchdogNumber > ARRAY_SIZE(spapr->wds)) {
+ return H_P2;
+ }
+ if (timeoutInMs <= WDT_MIN_TIMEOUT) {
+ return H_P3;
+ }
+
+ w = &spapr->wds[watchdogNumber - 1];
+ switch (timeoutAction) {
+ case PSERIES_WDTF_ACTION_HARD_POWER_OFF:
+ case PSERIES_WDTF_ACTION_HARD_RESTART:
+ case PSERIES_WDTF_ACTION_DUMP_RESTART:
+ w->action = timeoutAction;
+ break;
+ default:
+ return H_PARAMETER;
+ }
+ w->leave_others = FIELD_EX64(flags, PSERIES_WDTF, LEAVE_OTHER);
+ timer_mod(&w->timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + timeoutInMs);
+ trace_spapr_watchdog_start(flags, watchdogNumber, timeoutInMs);
+ break;
+ case PSERIES_WDTF_OP_STOP:
+ if (watchdogNumber == PSERIES_WDT_STOP_ALL) {
+ ret = watchdog_stop_all(spapr);
+ } else if (watchdogNumber <= ARRAY_SIZE(spapr->wds)) {
+ ret = watchdog_stop(watchdogNumber,
+ &spapr->wds[watchdogNumber - 1]);
+ } else {
+ return H_P2;
+ }
+ break;
+ case PSERIES_WDTF_OP_QUERY:
+ args[0] = FIELD_DP64(0, PSERIES_WDTQ, MIN_TIMEOUT, WDT_MIN_TIMEOUT);
+ args[0] = FIELD_DP64(args[0], PSERIES_WDTQ, NUM,
+ ARRAY_SIZE(spapr->wds));
+ trace_spapr_watchdog_query(args[0]);
+ break;
+ case PSERIES_WDTF_OP_QUERY_LPM:
+ if (watchdogNumber > ARRAY_SIZE(spapr->wds)) {
+ return H_P2;
+ }
+ args[0] = PSERIES_WDTQL_QUERY_NOT_STOPPED;
+ trace_spapr_watchdog_query_lpm(args[0]);
+ break;
+ default:
+ return H_PARAMETER;
+ }
+
+ return ret;
+}
+
+void spapr_watchdog_init(SpaprMachineState *spapr)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(spapr->wds); ++i) {
+ char name[16];
+ SpaprWatchdog *w = &spapr->wds[i];
+
+ snprintf(name, sizeof(name) - 1, "wdt%d", i + 1);
+ object_initialize_child_with_props(OBJECT(spapr), name, w,
+ sizeof(SpaprWatchdog),
+ TYPE_SPAPR_WDT,
+ &error_fatal, NULL);
+ qdev_realize(DEVICE(w), NULL, &error_fatal);
+ }
+}
+
+static bool watchdog_needed(void *opaque)
+{
+ SpaprWatchdog *w = opaque;
+
+ return timer_pending(&w->timer);
+}
+
+static const VMStateDescription vmstate_wdt = {
+ .name = "spapr_watchdog",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = watchdog_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_TIMER(timer, SpaprWatchdog),
+ VMSTATE_UINT8(action, SpaprWatchdog),
+ VMSTATE_UINT8(leave_others, SpaprWatchdog),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void spapr_wdt_realize(DeviceState *dev, Error **errp)
+{
+ SpaprWatchdog *w = SPAPR_WDT(dev);
+ Object *o = OBJECT(dev);
+
+ timer_init_ms(&w->timer, QEMU_CLOCK_VIRTUAL, watchdog_expired, w);
+
+ object_property_add_uint64_ptr(o, "expire",
+ (uint64_t *)&w->timer.expire_time,
+ OBJ_PROP_FLAG_READ);
+ object_property_add_uint8_ptr(o, "action", &w->action, OBJ_PROP_FLAG_READ);
+ object_property_add_uint8_ptr(o, "leaveOtherWatchdogsRunningOnTimeout",
+ &w->leave_others, OBJ_PROP_FLAG_READ);
+}
+
+static void spapr_wdt_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = spapr_wdt_realize;
+ dc->vmsd = &vmstate_wdt;
+ dc->user_creatable = false;
+}
+
+static const TypeInfo spapr_wdt_info = {
+ .name = TYPE_SPAPR_WDT,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SpaprWatchdog),
+ .class_init = spapr_wdt_class_init,
+};
+
+static void spapr_watchdog_register_types(void)
+{
+ spapr_register_hypercall(H_WATCHDOG, h_watchdog);
+ type_register_static(&spapr_wdt_info);
+}
+
+type_init(spapr_watchdog_register_types)
diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events
index e7523e2..89ccbcf 100644
--- a/hw/watchdog/trace-events
+++ b/hw/watchdog/trace-events
@@ -9,3 +9,10 @@ cmsdk_apb_watchdog_lock(uint32_t lock) "CMSDK APB watchdog: lock %" PRIu32
# wdt-aspeed.c
aspeed_wdt_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d"
aspeed_wdt_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64
+
+# spapr_watchdog.c
+spapr_watchdog_start(uint64_t flags, uint64_t num, uint64_t timeout) "Flags 0x%" PRIx64 " num=%" PRId64 " %" PRIu64 "ms"
+spapr_watchdog_stop(uint64_t num, uint64_t ret) "num=%" PRIu64 " ret=%" PRId64
+spapr_watchdog_query(uint64_t caps) "caps=0x%" PRIx64
+spapr_watchdog_query_lpm(uint64_t caps) "caps=0x%" PRIx64
+spapr_watchdog_expired(uint64_t num, unsigned action) "num=%" PRIu64 " action=%u"
diff --git a/include/hw/pci-host/pnv_phb3_regs.h b/include/hw/pci-host/pnv_phb3_regs.h
index a174ef1..38f8ce9 100644
--- a/include/hw/pci-host/pnv_phb3_regs.h
+++ b/include/hw/pci-host/pnv_phb3_regs.h
@@ -13,22 +13,6 @@
#include "qemu/host-utils.h"
/*
- * QEMU version of the GETFIELD/SETFIELD macros
- *
- * These are common with the PnvXive model.
- */
-static inline uint64_t GETFIELD(uint64_t mask, uint64_t word)
-{
- return (word & mask) >> ctz64(mask);
-}
-
-static inline uint64_t SETFIELD(uint64_t mask, uint64_t word,
- uint64_t value)
-{
- return (word & ~mask) | ((value << ctz64(mask)) & mask);
-}
-
-/*
* PBCQ XSCOM registers
*/
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 86cb7d7..b991194 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -189,7 +189,8 @@ DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10,
TYPE_PNV_CHIP_POWER10)
PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir);
-void pnv_phb_attach_root_port(PCIHostState *pci, const char *name);
+void pnv_phb_attach_root_port(PCIHostState *pci, const char *name,
+ int index, int chip_id);
#define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv")
typedef struct PnvMachineClass PnvMachineClass;
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 072dda2..530d739 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -164,6 +164,21 @@ struct SpaprMachineClass {
SpaprIrq *irq;
};
+#define WDT_MAX_WATCHDOGS 4 /* Maximum number of watchdog devices */
+
+#define TYPE_SPAPR_WDT "spapr-wdt"
+OBJECT_DECLARE_SIMPLE_TYPE(SpaprWatchdog, SPAPR_WDT)
+
+typedef struct SpaprWatchdog {
+ /*< private >*/
+ DeviceState parent_obj;
+ /*< public >*/
+
+ QEMUTimer timer;
+ uint8_t action; /* One of PSERIES_WDTF_ACTION_xxx */
+ uint8_t leave_others; /* leaveOtherWatchdogsRunningOnTimeout */
+} SpaprWatchdog;
+
/**
* SpaprMachineState:
*/
@@ -264,6 +279,8 @@ struct SpaprMachineState {
uint32_t FORM2_assoc_array[NUMA_NODES_MAX_NUM][FORM2_NUMA_ASSOC_SIZE];
Error *fwnmi_migration_blocker;
+
+ SpaprWatchdog wds[WDT_MAX_WATCHDOGS];
};
#define H_SUCCESS 0
@@ -344,6 +361,7 @@ struct SpaprMachineState {
#define H_P7 -60
#define H_P8 -61
#define H_P9 -62
+#define H_NOOP -63
#define H_UNSUPPORTED -67
#define H_OVERLAP -68
#define H_UNSUPPORTED_FLAG -256
@@ -564,8 +582,9 @@ struct SpaprMachineState {
#define H_SCM_HEALTH 0x400
#define H_RPT_INVALIDATE 0x448
#define H_SCM_FLUSH 0x44C
+#define H_WATCHDOG 0x45C
-#define MAX_HCALL_OPCODE H_SCM_FLUSH
+#define MAX_HCALL_OPCODE H_WATCHDOG
/* The hcalls above are standardized in PAPR and implemented by pHyp
* as well.
@@ -902,6 +921,7 @@ struct SpaprTceTable {
bool bypass;
bool need_vfio;
bool skipping_replay;
+ bool def_win;
int fd;
MemoryRegion root;
IOMMUMemoryRegion iommu;
@@ -1027,6 +1047,7 @@ extern const VMStateDescription vmstate_spapr_cap_large_decr;
extern const VMStateDescription vmstate_spapr_cap_ccf_assist;
extern const VMStateDescription vmstate_spapr_cap_fwnmi;
extern const VMStateDescription vmstate_spapr_cap_rpt_invalidate;
+extern const VMStateDescription vmstate_spapr_wdt;
static inline uint8_t spapr_get_cap(SpaprMachineState *spapr, int cap)
{
@@ -1063,4 +1084,7 @@ target_ulong spapr_vof_client_architecture_support(MachineState *ms,
target_ulong ovec_addr);
void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt);
+/* H_WATCHDOG */
+void spapr_watchdog_init(SpaprMachineState *spapr);
+
#endif /* HW_SPAPR_H */
diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c
index 976be5e..912b037 100644
--- a/target/ppc/cpu-models.c
+++ b/target/ppc/cpu-models.c
@@ -385,19 +385,19 @@
POWERPC_DEF_SVR("mpc8548e_v21", "MPC8548E v2.1",
CPU_POWERPC_MPC8548E_v21, POWERPC_SVR_8548E_v21, e500v2)
POWERPC_DEF_SVR("mpc8555_v10", "MPC8555 v1.0",
- CPU_POWERPC_MPC8555_v10, POWERPC_SVR_8555_v10, e500v2)
+ CPU_POWERPC_MPC8555_v10, POWERPC_SVR_8555_v10, e500v1)
POWERPC_DEF_SVR("mpc8555_v11", "MPC8555 v1.1",
- CPU_POWERPC_MPC8555_v11, POWERPC_SVR_8555_v11, e500v2)
+ CPU_POWERPC_MPC8555_v11, POWERPC_SVR_8555_v11, e500v1)
POWERPC_DEF_SVR("mpc8555e_v10", "MPC8555E v1.0",
- CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500v2)
+ CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500v1)
POWERPC_DEF_SVR("mpc8555e_v11", "MPC8555E v1.1",
- CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500v2)
+ CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500v1)
POWERPC_DEF_SVR("mpc8560_v10", "MPC8560 v1.0",
- CPU_POWERPC_MPC8560_v10, POWERPC_SVR_8560_v10, e500v2)
+ CPU_POWERPC_MPC8560_v10, POWERPC_SVR_8560_v10, e500v1)
POWERPC_DEF_SVR("mpc8560_v20", "MPC8560 v2.0",
- CPU_POWERPC_MPC8560_v20, POWERPC_SVR_8560_v20, e500v2)
+ CPU_POWERPC_MPC8560_v20, POWERPC_SVR_8560_v20, e500v1)
POWERPC_DEF_SVR("mpc8560_v21", "MPC8560 v2.1",
- CPU_POWERPC_MPC8560_v21, POWERPC_SVR_8560_v21, e500v2)
+ CPU_POWERPC_MPC8560_v21, POWERPC_SVR_8560_v21, e500v1)
POWERPC_DEF_SVR("mpc8567", "MPC8567",
CPU_POWERPC_MPC8567, POWERPC_SVR_8567, e500v2)
POWERPC_DEF_SVR("mpc8567e", "MPC8567E",
@@ -879,7 +879,6 @@ PowerPCCPUAlias ppc_cpu_aliases[] = {
{ "755", "755_v2.8" },
{ "goldfinger", "755_v2.8" },
{ "7400", "7400_v2.9" },
- { "max", "7400_v2.9" },
{ "g4", "7400_v2.9" },
{ "7410", "7410_v1.4" },
{ "nitro", "7410_v1.4" },
@@ -918,6 +917,6 @@ PowerPCCPUAlias ppc_cpu_aliases[] = {
#endif
{ "ppc32", "604" },
{ "ppc", "604" },
- { "default", "604" },
+
{ NULL, NULL }
};
diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h
index 76775a7..1326493 100644
--- a/target/ppc/cpu-models.h
+++ b/target/ppc/cpu-models.h
@@ -184,13 +184,13 @@ enum {
#define CPU_POWERPC_MPC8548E_v11 CPU_POWERPC_e500v2_v11
#define CPU_POWERPC_MPC8548E_v20 CPU_POWERPC_e500v2_v20
#define CPU_POWERPC_MPC8548E_v21 CPU_POWERPC_e500v2_v21
-#define CPU_POWERPC_MPC8555_v10 CPU_POWERPC_e500v2_v10
-#define CPU_POWERPC_MPC8555_v11 CPU_POWERPC_e500v2_v11
-#define CPU_POWERPC_MPC8555E_v10 CPU_POWERPC_e500v2_v10
-#define CPU_POWERPC_MPC8555E_v11 CPU_POWERPC_e500v2_v11
-#define CPU_POWERPC_MPC8560_v10 CPU_POWERPC_e500v2_v10
-#define CPU_POWERPC_MPC8560_v20 CPU_POWERPC_e500v2_v20
-#define CPU_POWERPC_MPC8560_v21 CPU_POWERPC_e500v2_v21
+#define CPU_POWERPC_MPC8555_v10 CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_MPC8555_v11 CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_MPC8555E_v10 CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_MPC8555E_v11 CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_MPC8560_v10 CPU_POWERPC_e500v1_v10
+#define CPU_POWERPC_MPC8560_v20 CPU_POWERPC_e500v1_v20
+#define CPU_POWERPC_MPC8560_v21 CPU_POWERPC_e500v1_v20
#define CPU_POWERPC_MPC8567 CPU_POWERPC_e500v2_v22
#define CPU_POWERPC_MPC8567E CPU_POWERPC_e500v2_v22
#define CPU_POWERPC_MPC8568 CPU_POWERPC_e500v2_v22
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 6d78078..7aaff9d 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -47,6 +47,18 @@
PPC_BIT32(bs))
#define PPC_BITMASK8(bs, be) ((PPC_BIT8(bs) - PPC_BIT8(be)) | PPC_BIT8(bs))
+/*
+ * QEMU version of the GETFIELD/SETFIELD macros from skiboot
+ *
+ * It might be better to use the existing extract64() and
+ * deposit64() but this means that all the register definitions will
+ * change and become incompatible with the ones found in skiboot.
+ */
+#define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1)
+#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m))
+#define SETFIELD(m, v, val) \
+ (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m)))
+
/*****************************************************************************/
/* Exception vectors definitions */
enum {
@@ -694,42 +706,42 @@ enum {
/*****************************************************************************/
/* Floating point status and control register */
-#define FPSCR_DRN2 34 /* Decimal Floating-Point rounding control */
-#define FPSCR_DRN1 33 /* Decimal Floating-Point rounding control */
-#define FPSCR_DRN0 32 /* Decimal Floating-Point rounding control */
-#define FPSCR_FX 31 /* Floating-point exception summary */
-#define FPSCR_FEX 30 /* Floating-point enabled exception summary */
-#define FPSCR_VX 29 /* Floating-point invalid operation exception summ. */
-#define FPSCR_OX 28 /* Floating-point overflow exception */
-#define FPSCR_UX 27 /* Floating-point underflow exception */
-#define FPSCR_ZX 26 /* Floating-point zero divide exception */
-#define FPSCR_XX 25 /* Floating-point inexact exception */
-#define FPSCR_VXSNAN 24 /* Floating-point invalid operation exception (sNan) */
-#define FPSCR_VXISI 23 /* Floating-point invalid operation exception (inf) */
-#define FPSCR_VXIDI 22 /* Floating-point invalid operation exception (inf) */
-#define FPSCR_VXZDZ 21 /* Floating-point invalid operation exception (zero) */
-#define FPSCR_VXIMZ 20 /* Floating-point invalid operation exception (inf) */
-#define FPSCR_VXVC 19 /* Floating-point invalid operation exception (comp) */
-#define FPSCR_FR 18 /* Floating-point fraction rounded */
-#define FPSCR_FI 17 /* Floating-point fraction inexact */
-#define FPSCR_C 16 /* Floating-point result class descriptor */
-#define FPSCR_FL 15 /* Floating-point less than or negative */
-#define FPSCR_FG 14 /* Floating-point greater than or negative */
-#define FPSCR_FE 13 /* Floating-point equal or zero */
-#define FPSCR_FU 12 /* Floating-point unordered or NaN */
-#define FPSCR_FPCC 12 /* Floating-point condition code */
-#define FPSCR_FPRF 12 /* Floating-point result flags */
-#define FPSCR_VXSOFT 10 /* Floating-point invalid operation exception (soft) */
-#define FPSCR_VXSQRT 9 /* Floating-point invalid operation exception (sqrt) */
-#define FPSCR_VXCVI 8 /* Floating-point invalid operation exception (int) */
-#define FPSCR_VE 7 /* Floating-point invalid operation exception enable */
-#define FPSCR_OE 6 /* Floating-point overflow exception enable */
-#define FPSCR_UE 5 /* Floating-point underflow exception enable */
-#define FPSCR_ZE 4 /* Floating-point zero divide exception enable */
-#define FPSCR_XE 3 /* Floating-point inexact exception enable */
-#define FPSCR_NI 2 /* Floating-point non-IEEE mode */
-#define FPSCR_RN1 1
-#define FPSCR_RN0 0 /* Floating-point rounding control */
+#define FPSCR_DRN2 PPC_BIT_NR(29) /* Decimal Floating-Point rounding ctrl. */
+#define FPSCR_DRN1 PPC_BIT_NR(30) /* Decimal Floating-Point rounding ctrl. */
+#define FPSCR_DRN0 PPC_BIT_NR(31) /* Decimal Floating-Point rounding ctrl. */
+#define FPSCR_FX PPC_BIT_NR(32) /* Floating-point exception summary */
+#define FPSCR_FEX PPC_BIT_NR(33) /* Floating-point enabled exception summ.*/
+#define FPSCR_VX PPC_BIT_NR(34) /* Floating-point invalid op. excp. summ.*/
+#define FPSCR_OX PPC_BIT_NR(35) /* Floating-point overflow exception */
+#define FPSCR_UX PPC_BIT_NR(36) /* Floating-point underflow exception */
+#define FPSCR_ZX PPC_BIT_NR(37) /* Floating-point zero divide exception */
+#define FPSCR_XX PPC_BIT_NR(38) /* Floating-point inexact exception */
+#define FPSCR_VXSNAN PPC_BIT_NR(39) /* Floating-point invalid op. excp (sNan)*/
+#define FPSCR_VXISI PPC_BIT_NR(40) /* Floating-point invalid op. excp (inf) */
+#define FPSCR_VXIDI PPC_BIT_NR(41) /* Floating-point invalid op. excp (inf) */
+#define FPSCR_VXZDZ PPC_BIT_NR(42) /* Floating-point invalid op. excp (zero)*/
+#define FPSCR_VXIMZ PPC_BIT_NR(43) /* Floating-point invalid op. excp (inf) */
+#define FPSCR_VXVC PPC_BIT_NR(44) /* Floating-point invalid op. excp (comp)*/
+#define FPSCR_FR PPC_BIT_NR(45) /* Floating-point fraction rounded */
+#define FPSCR_FI PPC_BIT_NR(46) /* Floating-point fraction inexact */
+#define FPSCR_C PPC_BIT_NR(47) /* Floating-point result class descriptor*/
+#define FPSCR_FL PPC_BIT_NR(48) /* Floating-point less than or negative */
+#define FPSCR_FG PPC_BIT_NR(49) /* Floating-point greater than or neg. */
+#define FPSCR_FE PPC_BIT_NR(50) /* Floating-point equal or zero */
+#define FPSCR_FU PPC_BIT_NR(51) /* Floating-point unordered or NaN */
+#define FPSCR_FPCC PPC_BIT_NR(51) /* Floating-point condition code */
+#define FPSCR_FPRF PPC_BIT_NR(51) /* Floating-point result flags */
+#define FPSCR_VXSOFT PPC_BIT_NR(53) /* Floating-point invalid op. excp (soft)*/
+#define FPSCR_VXSQRT PPC_BIT_NR(54) /* Floating-point invalid op. excp (sqrt)*/
+#define FPSCR_VXCVI PPC_BIT_NR(55) /* Floating-point invalid op. excp (int) */
+#define FPSCR_VE PPC_BIT_NR(56) /* Floating-point invalid op. excp enable*/
+#define FPSCR_OE PPC_BIT_NR(57) /* Floating-point overflow excp. enable */
+#define FPSCR_UE PPC_BIT_NR(58) /* Floating-point underflow excp. enable */
+#define FPSCR_ZE PPC_BIT_NR(59) /* Floating-point zero divide excp enable*/
+#define FPSCR_XE PPC_BIT_NR(60) /* Floating-point inexact excp. enable */
+#define FPSCR_NI PPC_BIT_NR(61) /* Floating-point non-IEEE mode */
+#define FPSCR_RN1 PPC_BIT_NR(62)
+#define FPSCR_RN0 PPC_BIT_NR(63) /* Floating-point rounding control */
/* Invalid operation exception summary */
#define FPSCR_IX ((1 << FPSCR_VXSNAN) | (1 << FPSCR_VXISI) | \
(1 << FPSCR_VXIDI) | (1 << FPSCR_VXZDZ) | \
@@ -2277,6 +2289,8 @@ enum {
PPC2_ISA310 = 0x0000000000100000ULL,
/* lwsync instruction */
PPC2_MEM_LWSYNC = 0x0000000000200000ULL,
+ /* ISA 2.06 BCD assist instructions */
+ PPC2_BCDA_ISA206 = 0x0000000000400000ULL,
#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \
PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
@@ -2285,7 +2299,8 @@ enum {
PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \
PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \
PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206 | \
- PPC2_ISA300 | PPC2_ISA310 | PPC2_MEM_LWSYNC)
+ PPC2_ISA300 | PPC2_ISA310 | PPC2_MEM_LWSYNC | \
+ PPC2_BCDA_ISA206)
};
/*****************************************************************************/
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index c16cb8d..86ad284 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -47,6 +47,10 @@
#include "spr_common.h"
#include "power8-pmu.h"
+#ifndef CONFIG_USER_ONLY
+#include "hw/boards.h"
+#endif
+
/* #define PPC_DEBUG_SPR */
/* #define USE_APPLE_GDB */
@@ -5985,7 +5989,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
PPC2_FP_TST_ISA206 | PPC2_FP_CVT_S64 |
- PPC2_PM_ISA206 | PPC2_MEM_LWSYNC;
+ PPC2_PM_ISA206 | PPC2_MEM_LWSYNC | PPC2_BCDA_ISA206;
pcc->msr_mask = (1ull << MSR_SF) |
(1ull << MSR_VR) |
(1ull << MSR_VSX) |
@@ -6159,7 +6163,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 |
PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
- PPC2_TM | PPC2_PM_ISA206 | PPC2_MEM_LWSYNC;
+ PPC2_TM | PPC2_PM_ISA206 | PPC2_MEM_LWSYNC |
+ PPC2_BCDA_ISA206;
pcc->msr_mask = (1ull << MSR_SF) |
(1ull << MSR_HV) |
(1ull << MSR_TM) |
@@ -6379,7 +6384,8 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 |
PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
- PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL | PPC2_MEM_LWSYNC;
+ PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL | PPC2_MEM_LWSYNC |
+ PPC2_BCDA_ISA206;
pcc->msr_mask = (1ull << MSR_SF) |
(1ull << MSR_HV) |
(1ull << MSR_TM) |
@@ -6597,7 +6603,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL | PPC2_ISA310 |
- PPC2_MEM_LWSYNC;
+ PPC2_MEM_LWSYNC | PPC2_BCDA_ISA206;
pcc->msr_mask = (1ull << MSR_SF) |
(1ull << MSR_HV) |
(1ull << MSR_TM) |
@@ -6963,6 +6969,21 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name)
}
}
+ /*
+ * All ppc CPUs represent hardware that exists in the real world, i.e.: we
+ * do not have a "max" CPU with all possible emulated features enabled.
+ * Return the default CPU type for the machine because that has greater
+ * chance of being useful as the "max" CPU.
+ */
+#if !defined(CONFIG_USER_ONLY)
+ if (strcmp(name, "max") == 0) {
+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
+ if (mc) {
+ return object_class_by_name(mc->default_cpu_type);
+ }
+ }
+#endif
+
cpu_model = g_ascii_strdown(name, -1);
p = ppc_cpu_lookup_alias(cpu_model);
if (p) {
diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c
index 0d01ac3..5ba74b2 100644
--- a/target/ppc/dfp_helper.c
+++ b/target/ppc/dfp_helper.c
@@ -1391,3 +1391,68 @@ DFP_HELPER_SHIFT(DSCLI, 64, 1)
DFP_HELPER_SHIFT(DSCLIQ, 128, 1)
DFP_HELPER_SHIFT(DSCRI, 64, 0)
DFP_HELPER_SHIFT(DSCRIQ, 128, 0)
+
+target_ulong helper_CDTBCD(target_ulong s)
+{
+ uint64_t res = 0;
+ uint32_t dec32, declets;
+ uint8_t bcd[6];
+ int i, w, sh;
+ decNumber a;
+
+ for (w = 1; w >= 0; w--) {
+ res <<= 32;
+ declets = extract64(s, 32 * w, 20);
+ if (declets) {
+ /* decimal32 with zero exponent and word "w" declets */
+ dec32 = (0x225ULL << 20) | declets;
+ decimal32ToNumber((decimal32 *)&dec32, &a);
+ decNumberGetBCD(&a, bcd);
+ for (i = 0; i < a.digits; i++) {
+ sh = 4 * (a.digits - 1 - i);
+ res |= (uint64_t)bcd[i] << sh;
+ }
+ }
+ }
+
+ return res;
+}
+
+target_ulong helper_CBCDTD(target_ulong s)
+{
+ uint64_t res = 0;
+ uint32_t dec32;
+ uint8_t bcd[6];
+ int w, i, offs;
+ decNumber a;
+ decContext context;
+
+ decContextDefault(&context, DEC_INIT_DECIMAL32);
+
+ for (w = 1; w >= 0; w--) {
+ res <<= 32;
+ decNumberZero(&a);
+ /* Extract each BCD field of word "w" */
+ for (i = 5; i >= 0; i--) {
+ offs = 4 * (5 - i) + 32 * w;
+ bcd[i] = extract64(s, offs, 4);
+ if (bcd[i] > 9) {
+ /*
+ * If the field value is greater than 9, the results are
+ * undefined. We could use a fixed value like 0 or 9, but
+ * an and with 9 seems to better match the hardware behavior.
+ */
+ bcd[i] &= 9;
+ }
+ }
+
+ /* Create a decNumber with the BCD values and convert to decimal32 */
+ decNumberSetBCD(&a, bcd, 6);
+ decimal32FromNumber((decimal32 *)&dec32, &a, &context);
+
+ /* Extract the two declets from the decimal32 value */
+ res |= dec32 & 0xfffff;
+ }
+
+ return res;
+}
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index d627cfe..ed0641a 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -54,6 +54,8 @@ DEF_HELPER_3(sraw, tl, env, tl, tl)
DEF_HELPER_FLAGS_2(CFUGED, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(PDEPD, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(PEXTD, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_1(CDTBCD, TCG_CALL_NO_RWG_SE, tl, tl)
+DEF_HELPER_FLAGS_1(CBCDTD, TCG_CALL_NO_RWG_SE, tl, tl)
#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)
@@ -204,14 +206,14 @@ DEF_HELPER_FLAGS_5(vadduws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
DEF_HELPER_FLAGS_5(vsububs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
DEF_HELPER_FLAGS_5(vsubuhs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
DEF_HELPER_FLAGS_5(vsubuws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_3(vadduqm, TCG_CALL_NO_RWG, void, avr, avr, avr)
-DEF_HELPER_FLAGS_4(vaddecuq, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
-DEF_HELPER_FLAGS_4(vaddeuqm, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
-DEF_HELPER_FLAGS_3(vaddcuq, TCG_CALL_NO_RWG, void, avr, avr, avr)
-DEF_HELPER_FLAGS_3(vsubuqm, TCG_CALL_NO_RWG, void, avr, avr, avr)
-DEF_HELPER_FLAGS_4(vsubecuq, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
-DEF_HELPER_FLAGS_4(vsubeuqm, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
-DEF_HELPER_FLAGS_3(vsubcuq, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VADDUQM, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_4(VADDECUQ, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
+DEF_HELPER_FLAGS_4(VADDEUQM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VADDCUQ, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VSUBUQM, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_4(VSUBECUQ, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
+DEF_HELPER_FLAGS_4(VSUBEUQM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VSUBCUQ, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_4(vsldoi, TCG_CALL_NO_RWG, void, avr, avr, avr, i32)
DEF_HELPER_FLAGS_3(vextractub, TCG_CALL_NO_RWG, void, avr, avr, i32)
DEF_HELPER_FLAGS_3(vextractuh, TCG_CALL_NO_RWG, void, avr, avr, i32)
@@ -318,7 +320,7 @@ DEF_HELPER_FLAGS_3(vbpermq, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_3(vpmsumb, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_3(vpmsumh, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_3(vpmsumw, TCG_CALL_NO_RWG, void, avr, avr, avr)
-DEF_HELPER_FLAGS_3(vpmsumd, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VPMSUMD, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_2(vextublx, TCG_CALL_NO_RWG, tl, tl, avr)
DEF_HELPER_FLAGS_2(vextuhlx, TCG_CALL_NO_RWG, tl, tl, avr)
DEF_HELPER_FLAGS_2(vextuwlx, TCG_CALL_NO_RWG, tl, tl, avr)
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 6ea48d5..f7653ef 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -21,11 +21,11 @@
@A ...... frt:5 fra:5 frb:5 frc:5 ..... rc:1 &A
&D rt ra si:int64_t
-@D ...... rt:5 ra:5 si:s16 &D
+@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
+@D_bfs ...... bf:3 . l:1 ra:5 imm:s16 &D_bf
+@D_bfu ...... bf:3 . l:1 ra:5 imm:16 &D_bf
%dq_si 4:s12 !function=times_16
%dq_rtp 22:4 !function=times_2
@@ -38,7 +38,7 @@
@DQ_TSXP ...... ..... ra:5 ............ .... &D si=%dq_si rt=%rt_tsxp
%ds_si 2:s14 !function=times_4
-@DS ...... rt:5 ra:5 .............. .. &D si=%ds_si
+@DS ...... rt:5 ra:5 .............. .. &D si=%ds_si
%ds_rtp 22:4 !function=times_2
@DS_rtp ...... ....0 ra:5 .............. .. &D rt=%ds_rtp si=%ds_si
@@ -49,10 +49,10 @@
&DX rt d
%dx_d 6:s10 16:5 0:1
-@DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d
+@DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d
&VA vrt vra vrb rc
-@VA ...... vrt:5 vra:5 vrb:5 rc:5 ...... &VA
+@VA ...... vrt:5 vra:5 vrb:5 rc:5 ...... &VA
&VC vrt vra vrb rc:bool
@VC ...... vrt:5 vra:5 vrb:5 rc:1 .......... &VC
@@ -61,7 +61,7 @@
@VN ...... vrt:5 vra:5 vrb:5 .. sh:3 ...... &VN
&VX vrt vra vrb
-@VX ...... vrt:5 vra:5 vrb:5 .......... . &VX
+@VX ...... vrt:5 vra:5 vrb:5 .......... . &VX
&VX_bf bf vra vrb
@VX_bf ...... bf:3 .. vra:5 vrb:5 ........... &VX_bf
@@ -76,17 +76,20 @@
@VX_tb_rc ...... vrt:5 ..... vrb:5 rc:1 .......... &VX_tb_rc
&VX_uim4 vrt uim vrb
-@VX_uim4 ...... vrt:5 . uim:4 vrb:5 ........... &VX_uim4
+@VX_uim4 ...... vrt:5 . uim:4 vrb:5 ........... &VX_uim4
&VX_tb vrt vrb
-@VX_tb ...... vrt:5 ..... vrb:5 ........... &VX_tb
+@VX_tb ...... vrt:5 ..... vrb:5 ........... &VX_tb
&X rt ra rb
-@X ...... rt:5 ra:5 rb:5 .......... . &X
+@X ...... rt:5 ra:5 rb:5 .......... . &X
&X_rc rt ra rb rc:bool
@X_rc ...... rt:5 ra:5 rb:5 .......... rc:1 &X_rc
+&X_sa rs ra
+@X_sa ...... rs:5 ra:5 ..... .......... . &X_sa
+
%x_frtp 22:4 !function=times_2
%x_frap 17:4 !function=times_2
%x_frbp 12:4 !function=times_2
@@ -94,9 +97,15 @@
@X_tp_a_bp_rc ...... ....0 ra:5 ....0 .......... rc:1 &X_rc rt=%x_frtp rb=%x_frbp
+&X_t rt
+@X_t ...... rt:5 ..... ..... .......... . &X_t
+
&X_tb rt rb
@X_tb ...... rt:5 ..... rb:5 .......... . &X_tb
+&X_t_rc rt rc:bool
+@X_t_rc ...... rt:5 ..... ..... .......... rc:1 &X_t_rc
+
&X_tb_rc rt rb rc:bool
@X_tb_rc ...... rt:5 ..... rb:5 .......... rc:1 &X_tb_rc
@@ -107,7 +116,7 @@
@X_t_bp_rc ...... rt:5 ..... ....0 .......... rc:1 &X_tb_rc rb=%x_frbp
&X_bi rt bi
-@X_bi ...... rt:5 bi:5 ----- .......... - &X_bi
+@X_bi ...... rt:5 bi:5 ..... .......... . &X_bi
&X_bf bf ra rb
@X_bf ...... bf:3 .. ra:5 rb:5 .......... . &X_bf
@@ -122,7 +131,13 @@
@X_bf_uim_bp ...... bf:3 . uim:6 ....0 .......... . &X_bf_uim rb=%x_frbp
&X_bfl bf l:bool ra rb
-@X_bfl ...... bf:3 - l:1 ra:5 rb:5 ..........- &X_bfl
+@X_bfl ...... bf:3 . l:1 ra:5 rb:5 .......... . &X_bfl
+
+&X_imm2 rt imm
+@X_imm2 ...... rt:5 ..... ... imm:2 .......... . &X_imm2
+
+&X_imm3 rt imm
+@X_imm3 ...... rt:5 ..... .. imm:3 .......... . &X_imm3
%x_xt 0:1 21:5
&X_imm5 xt imm:uint8_t vrb
@@ -299,6 +314,12 @@ CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
PDEPD 011111 ..... ..... ..... 0010011100 - @X
PEXTD 011111 ..... ..... ..... 0010111100 - @X
+## BCD Assist
+
+ADDG6S 011111 ..... ..... ..... - 001001010 - @X
+CDTBCD 011111 ..... ..... ----- 0100011010 - @X_sa
+CBCDTD 011111 ..... ..... ----- 0100111010 - @X_sa
+
### Float-Point Load Instructions
LFS 110000 ..... ..... ................ @D
@@ -334,6 +355,16 @@ SETBCR 011111 ..... ..... ----- 0110100000 - @X_bi
SETNBC 011111 ..... ..... ----- 0111000000 - @X_bi
SETNBCR 011111 ..... ..... ----- 0111100000 - @X_bi
+### Move To/From FPSCR
+
+MFFS 111111 ..... 00000 ----- 1001000111 . @X_t_rc
+MFFSCE 111111 ..... 00001 ----- 1001000111 - @X_t
+MFFSCRN 111111 ..... 10110 ..... 1001000111 - @X_tb
+MFFSCDRN 111111 ..... 10100 ..... 1001000111 - @X_tb
+MFFSCRNI 111111 ..... 10111 ---.. 1001000111 - @X_imm2
+MFFSCDRNI 111111 ..... 10101 --... 1001000111 - @X_imm3
+MFFSL 111111 ..... 11000 ----- 1001000111 - @X_t
+
### Decimal Floating-Point Arithmetic Instructions
DADD 111011 ..... ..... ..... 0000000010 . @X_rc
@@ -426,6 +457,10 @@ DSCLIQ 111111 ..... ..... ...... 001000010 . @Z22_tap_sh_rc
DSCRI 111011 ..... ..... ...... 001100010 . @Z22_ta_sh_rc
DSCRIQ 111111 ..... ..... ...... 001100010 . @Z22_tap_sh_rc
+## Vector Exclusive-OR-based Instructions
+
+VPMSUMD 000100 ..... ..... ..... 10011001000 @VX
+
## Vector Integer Instructions
VCMPEQUB 000100 ..... ..... ..... . 0000000110 @VC
@@ -546,6 +581,18 @@ VRLQNM 000100 ..... ..... ..... 00101000101 @VX
## Vector Integer Arithmetic Instructions
+VADDCUQ 000100 ..... ..... ..... 00101000000 @VX
+VADDUQM 000100 ..... ..... ..... 00100000000 @VX
+
+VADDEUQM 000100 ..... ..... ..... ..... 111100 @VA
+VADDECUQ 000100 ..... ..... ..... ..... 111101 @VA
+
+VSUBCUQ 000100 ..... ..... ..... 10101000000 @VX
+VSUBUQM 000100 ..... ..... ..... 10100000000 @VX
+
+VSUBECUQ 000100 ..... ..... ..... ..... 111111 @VA
+VSUBEUQM 000100 ..... ..... ..... ..... 111110 @VA
+
VEXTSB2W 000100 ..... 10000 ..... 11000000010 @VX_tb
VEXTSH2W 000100 ..... 10001 ..... 11000000010 @VX_tb
VEXTSB2D 000100 ..... 11000 ..... 11000000010 @VX_tb
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 3ae03f7..d905f07 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -1484,52 +1484,24 @@ PMSUM(vpmsumb, u8, u16, uint16_t)
PMSUM(vpmsumh, u16, u32, uint32_t)
PMSUM(vpmsumw, u32, u64, uint64_t)
-void helper_vpmsumd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_VPMSUMD(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
-
-#ifdef CONFIG_INT128
- int i, j;
- __uint128_t prod[2];
-
- VECTOR_FOR_INORDER_I(i, u64) {
- prod[i] = 0;
- for (j = 0; j < 64; j++) {
- if (a->u64[i] & (1ull << j)) {
- prod[i] ^= (((__uint128_t)b->u64[i]) << j);
- }
- }
- }
-
- r->u128 = prod[0] ^ prod[1];
-
-#else
int i, j;
- ppc_avr_t prod[2];
-
- VECTOR_FOR_INORDER_I(i, u64) {
- prod[i].VsrD(1) = prod[i].VsrD(0) = 0;
- for (j = 0; j < 64; j++) {
- if (a->u64[i] & (1ull << j)) {
- ppc_avr_t bshift;
- if (j == 0) {
- bshift.VsrD(0) = 0;
- bshift.VsrD(1) = b->u64[i];
- } else {
- bshift.VsrD(0) = b->u64[i] >> (64 - j);
- bshift.VsrD(1) = b->u64[i] << j;
- }
- prod[i].VsrD(1) ^= bshift.VsrD(1);
- prod[i].VsrD(0) ^= bshift.VsrD(0);
+ Int128 tmp, prod[2] = {int128_zero(), int128_zero()};
+
+ for (j = 0; j < 64; j++) {
+ for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
+ if (a->VsrD(i) & (1ull << j)) {
+ tmp = int128_make64(b->VsrD(i));
+ tmp = int128_lshift(tmp, j);
+ prod[i] = int128_xor(prod[i], tmp);
}
}
}
- r->VsrD(1) = prod[0].VsrD(1) ^ prod[1].VsrD(1);
- r->VsrD(0) = prod[0].VsrD(0) ^ prod[1].VsrD(0);
-#endif
+ r->s128 = int128_xor(prod[0], prod[1]);
}
-
#if HOST_BIG_ENDIAN
#define PKBIG 1
#else
@@ -2204,189 +2176,66 @@ VGENERIC_DO(popcntd, u64)
#undef VGENERIC_DO
-#if HOST_BIG_ENDIAN
-#define QW_ONE { .u64 = { 0, 1 } }
-#else
-#define QW_ONE { .u64 = { 1, 0 } }
-#endif
-
-#ifndef CONFIG_INT128
-
-static inline void avr_qw_not(ppc_avr_t *t, ppc_avr_t a)
-{
- t->u64[0] = ~a.u64[0];
- t->u64[1] = ~a.u64[1];
-}
-
-static int avr_qw_cmpu(ppc_avr_t a, ppc_avr_t b)
-{
- if (a.VsrD(0) < b.VsrD(0)) {
- return -1;
- } else if (a.VsrD(0) > b.VsrD(0)) {
- return 1;
- } else if (a.VsrD(1) < b.VsrD(1)) {
- return -1;
- } else if (a.VsrD(1) > b.VsrD(1)) {
- return 1;
- } else {
- return 0;
- }
-}
-
-static void avr_qw_add(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
-{
- t->VsrD(1) = a.VsrD(1) + b.VsrD(1);
- t->VsrD(0) = a.VsrD(0) + b.VsrD(0) +
- (~a.VsrD(1) < b.VsrD(1));
-}
-
-static int avr_qw_addc(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
-{
- ppc_avr_t not_a;
- t->VsrD(1) = a.VsrD(1) + b.VsrD(1);
- t->VsrD(0) = a.VsrD(0) + b.VsrD(0) +
- (~a.VsrD(1) < b.VsrD(1));
- avr_qw_not(&not_a, a);
- return avr_qw_cmpu(not_a, b) < 0;
-}
-
-#endif
-
-void helper_vadduqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_VADDUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
-#ifdef CONFIG_INT128
- r->u128 = a->u128 + b->u128;
-#else
- avr_qw_add(r, *a, *b);
-#endif
+ r->s128 = int128_add(a->s128, b->s128);
}
-void helper_vaddeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_VADDEUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
-#ifdef CONFIG_INT128
- r->u128 = a->u128 + b->u128 + (c->u128 & 1);
-#else
-
- if (c->VsrD(1) & 1) {
- ppc_avr_t tmp;
-
- tmp.VsrD(0) = 0;
- tmp.VsrD(1) = c->VsrD(1) & 1;
- avr_qw_add(&tmp, *a, tmp);
- avr_qw_add(r, tmp, *b);
- } else {
- avr_qw_add(r, *a, *b);
- }
-#endif
+ r->s128 = int128_add(int128_add(a->s128, b->s128),
+ int128_make64(int128_getlo(c->s128) & 1));
}
-void helper_vaddcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_VADDCUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
-#ifdef CONFIG_INT128
- r->u128 = (~a->u128 < b->u128);
-#else
- ppc_avr_t not_a;
-
- avr_qw_not(&not_a, *a);
-
+ r->VsrD(1) = int128_ult(int128_not(a->s128), b->s128);
r->VsrD(0) = 0;
- r->VsrD(1) = (avr_qw_cmpu(not_a, *b) < 0);
-#endif
}
-void helper_vaddecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_VADDECUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
-#ifdef CONFIG_INT128
- int carry_out = (~a->u128 < b->u128);
- if (!carry_out && (c->u128 & 1)) {
- carry_out = ((a->u128 + b->u128 + 1) == 0) &&
- ((a->u128 != 0) || (b->u128 != 0));
- }
- r->u128 = carry_out;
-#else
-
- int carry_in = c->VsrD(1) & 1;
- int carry_out = 0;
- ppc_avr_t tmp;
-
- carry_out = avr_qw_addc(&tmp, *a, *b);
+ bool carry_out = int128_ult(int128_not(a->s128), b->s128),
+ carry_in = int128_getlo(c->s128) & 1;
if (!carry_out && carry_in) {
- ppc_avr_t one = QW_ONE;
- carry_out = avr_qw_addc(&tmp, tmp, one);
+ carry_out = (int128_nz(a->s128) || int128_nz(b->s128)) &&
+ int128_eq(int128_add(a->s128, b->s128), int128_makes64(-1));
}
+
r->VsrD(0) = 0;
r->VsrD(1) = carry_out;
-#endif
}
-void helper_vsubuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_VSUBUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
-#ifdef CONFIG_INT128
- r->u128 = a->u128 - b->u128;
-#else
- ppc_avr_t tmp;
- ppc_avr_t one = QW_ONE;
-
- avr_qw_not(&tmp, *b);
- avr_qw_add(&tmp, *a, tmp);
- avr_qw_add(r, tmp, one);
-#endif
+ r->s128 = int128_sub(a->s128, b->s128);
}
-void helper_vsubeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_VSUBEUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
-#ifdef CONFIG_INT128
- r->u128 = a->u128 + ~b->u128 + (c->u128 & 1);
-#else
- ppc_avr_t tmp, sum;
-
- avr_qw_not(&tmp, *b);
- avr_qw_add(&sum, *a, tmp);
-
- tmp.VsrD(0) = 0;
- tmp.VsrD(1) = c->VsrD(1) & 1;
- avr_qw_add(r, sum, tmp);
-#endif
+ r->s128 = int128_add(int128_add(a->s128, int128_not(b->s128)),
+ int128_make64(int128_getlo(c->s128) & 1));
}
-void helper_vsubcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_VSUBCUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
-#ifdef CONFIG_INT128
- r->u128 = (~a->u128 < ~b->u128) ||
- (a->u128 + ~b->u128 == (__uint128_t)-1);
-#else
- int carry = (avr_qw_cmpu(*a, *b) > 0);
- if (!carry) {
- ppc_avr_t tmp;
- avr_qw_not(&tmp, *b);
- avr_qw_add(&tmp, *a, tmp);
- carry = ((tmp.VsrSD(0) == -1ull) && (tmp.VsrSD(1) == -1ull));
- }
+ Int128 tmp = int128_not(b->s128);
+
+ r->VsrD(1) = int128_ult(int128_not(a->s128), tmp) ||
+ int128_eq(int128_add(a->s128, tmp), int128_makes64(-1));
r->VsrD(0) = 0;
- r->VsrD(1) = carry;
-#endif
}
-void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_VSUBECUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
-#ifdef CONFIG_INT128
- r->u128 =
- (~a->u128 < ~b->u128) ||
- ((c->u128 & 1) && (a->u128 + ~b->u128 == (__uint128_t)-1));
-#else
- int carry_in = c->VsrD(1) & 1;
- int carry_out = (avr_qw_cmpu(*a, *b) > 0);
- if (!carry_out && carry_in) {
- ppc_avr_t tmp;
- avr_qw_not(&tmp, *b);
- avr_qw_add(&tmp, *a, tmp);
- carry_out = ((tmp.VsrD(0) == -1ull) && (tmp.VsrD(1) == -1ull));
- }
+ Int128 tmp = int128_not(b->s128);
+ bool carry_out = int128_ult(int128_not(a->s128), tmp),
+ carry_in = int128_getlo(c->s128) & 1;
+ r->VsrD(1) = carry_out || (carry_in && int128_eq(int128_add(a->s128, tmp),
+ int128_makes64(-1)));
r->VsrD(0) = 0;
- r->VsrD(1) = carry_out;
-#endif
}
#define BCD_PLUS_PREF_1 0xC
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 2add128..467f304 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -159,9 +159,6 @@ EXTRACT_HELPER(FPL, 25, 1);
EXTRACT_HELPER(FPFLM, 17, 8);
EXTRACT_HELPER(FPW, 16, 1);
-/* mffscrni */
-EXTRACT_HELPER(RM, 11, 2);
-
/* addpcis */
EXTRACT_HELPER_SPLIT_3(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0)
#if defined(TARGET_PPC64)
diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc
index 1aab32b..cb0097b 100644
--- a/target/ppc/translate/fixedpoint-impl.c.inc
+++ b/target/ppc/translate/fixedpoint-impl.c.inc
@@ -492,3 +492,54 @@ static bool trans_PEXTD(DisasContext *ctx, arg_X *a)
#endif
return true;
}
+
+static bool trans_ADDG6S(DisasContext *ctx, arg_X *a)
+{
+ const uint64_t carry_bits = 0x1111111111111111ULL;
+ TCGv t0, t1, carry, zero = tcg_constant_tl(0);
+
+ REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206);
+
+ t0 = tcg_temp_new();
+ t1 = tcg_const_tl(0);
+ carry = tcg_const_tl(0);
+
+ for (int i = 0; i < 16; i++) {
+ tcg_gen_shri_tl(t0, cpu_gpr[a->ra], i * 4);
+ tcg_gen_andi_tl(t0, t0, 0xf);
+ tcg_gen_add_tl(t1, t1, t0);
+
+ tcg_gen_shri_tl(t0, cpu_gpr[a->rb], i * 4);
+ tcg_gen_andi_tl(t0, t0, 0xf);
+ tcg_gen_add_tl(t1, t1, t0);
+
+ tcg_gen_andi_tl(t1, t1, 0x10);
+ tcg_gen_setcond_tl(TCG_COND_NE, t1, t1, zero);
+
+ tcg_gen_shli_tl(t0, t1, i * 4);
+ tcg_gen_or_tl(carry, carry, t0);
+ }
+
+ tcg_gen_xori_tl(carry, carry, (target_long)carry_bits);
+ tcg_gen_muli_tl(cpu_gpr[a->rt], carry, 6);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(carry);
+
+ return true;
+}
+
+static bool trans_CDTBCD(DisasContext *ctx, arg_X_sa *a)
+{
+ REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206);
+ gen_helper_CDTBCD(cpu_gpr[a->ra], cpu_gpr[a->rs]);
+ return true;
+}
+
+static bool trans_CBCDTD(DisasContext *ctx, arg_X_sa *a)
+{
+ REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206);
+ gen_helper_CBCDTD(cpu_gpr[a->ra], cpu_gpr[a->rs]);
+ return true;
+}
diff --git a/target/ppc/translate/fp-impl.c.inc b/target/ppc/translate/fp-impl.c.inc
index f9b58b8..319513d 100644
--- a/target/ppc/translate/fp-impl.c.inc
+++ b/target/ppc/translate/fp-impl.c.inc
@@ -615,141 +615,162 @@ static void gen_mcrfs(DisasContext *ctx)
tcg_temp_free_i64(tnew_fpscr);
}
-/* mffs */
-static void gen_mffs(DisasContext *ctx)
+static TCGv_i64 place_from_fpscr(int rt, uint64_t mask)
{
- TCGv_i64 t0;
- if (unlikely(!ctx->fpu_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_FPU);
- return;
- }
- t0 = tcg_temp_new_i64();
+ TCGv_i64 fpscr = tcg_temp_new_i64();
+ TCGv_i64 fpscr_masked = tcg_temp_new_i64();
+
+ tcg_gen_extu_tl_i64(fpscr, cpu_fpscr);
+ tcg_gen_andi_i64(fpscr_masked, fpscr, mask);
+ set_fpr(rt, fpscr_masked);
+
+ tcg_temp_free_i64(fpscr_masked);
+
+ return fpscr;
+}
+
+static void store_fpscr_masked(TCGv_i64 fpscr, uint64_t clear_mask,
+ TCGv_i64 set_mask, uint32_t store_mask)
+{
+ TCGv_i64 fpscr_masked = tcg_temp_new_i64();
+ TCGv_i32 st_mask = tcg_constant_i32(store_mask);
+
+ tcg_gen_andi_i64(fpscr_masked, fpscr, ~clear_mask);
+ tcg_gen_or_i64(fpscr_masked, fpscr_masked, set_mask);
+ gen_helper_store_fpscr(cpu_env, fpscr_masked, st_mask);
+
+ tcg_temp_free_i64(fpscr_masked);
+}
+
+static bool trans_MFFS(DisasContext *ctx, arg_X_t_rc *a)
+{
+ TCGv_i64 fpscr;
+
+ REQUIRE_FPU(ctx);
+
gen_reset_fpstatus();
- tcg_gen_extu_tl_i64(t0, cpu_fpscr);
- set_fpr(rD(ctx->opcode), t0);
- if (unlikely(Rc(ctx->opcode))) {
+ fpscr = place_from_fpscr(a->rt, UINT64_MAX);
+ if (a->rc) {
gen_set_cr1_from_fpscr(ctx);
}
- tcg_temp_free_i64(t0);
+
+ tcg_temp_free_i64(fpscr);
+
+ return true;
}
-/* mffsl */
-static void gen_mffsl(DisasContext *ctx)
+static bool trans_MFFSCE(DisasContext *ctx, arg_X_t *a)
{
- TCGv_i64 t0;
+ TCGv_i64 fpscr;
- if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
- return gen_mffs(ctx);
- }
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_FPU(ctx);
- if (unlikely(!ctx->fpu_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_FPU);
- return;
- }
- t0 = tcg_temp_new_i64();
gen_reset_fpstatus();
- tcg_gen_extu_tl_i64(t0, cpu_fpscr);
- /* Mask everything except mode, status, and enables. */
- tcg_gen_andi_i64(t0, t0, FP_DRN | FP_STATUS | FP_ENABLES | FP_RN);
- set_fpr(rD(ctx->opcode), t0);
- tcg_temp_free_i64(t0);
+ fpscr = place_from_fpscr(a->rt, UINT64_MAX);
+ store_fpscr_masked(fpscr, FP_ENABLES, tcg_constant_i64(0), 0x0003);
+
+ tcg_temp_free_i64(fpscr);
+
+ return true;
}
-/* mffsce */
-static void gen_mffsce(DisasContext *ctx)
+static bool trans_MFFSCRN(DisasContext *ctx, arg_X_tb *a)
{
- TCGv_i64 t0;
- TCGv_i32 mask;
-
- if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
- return gen_mffs(ctx);
- }
+ TCGv_i64 t1, fpscr;
- if (unlikely(!ctx->fpu_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_FPU);
- return;
- }
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_FPU(ctx);
- t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ get_fpr(t1, a->rb);
+ tcg_gen_andi_i64(t1, t1, FP_RN);
gen_reset_fpstatus();
- tcg_gen_extu_tl_i64(t0, cpu_fpscr);
- set_fpr(rD(ctx->opcode), t0);
+ fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
+ store_fpscr_masked(fpscr, FP_RN, t1, 0x0001);
- /* Clear exception enable bits in the FPSCR. */
- tcg_gen_andi_i64(t0, t0, ~FP_ENABLES);
- mask = tcg_const_i32(0x0003);
- gen_helper_store_fpscr(cpu_env, t0, mask);
+ tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(fpscr);
- tcg_temp_free_i32(mask);
- tcg_temp_free_i64(t0);
+ return true;
}
-static void gen_helper_mffscrn(DisasContext *ctx, TCGv_i64 t1)
+static bool trans_MFFSCDRN(DisasContext *ctx, arg_X_tb *a)
{
- TCGv_i64 t0 = tcg_temp_new_i64();
- TCGv_i32 mask = tcg_const_i32(0x0001);
+ TCGv_i64 t1, fpscr;
- gen_reset_fpstatus();
- tcg_gen_extu_tl_i64(t0, cpu_fpscr);
- tcg_gen_andi_i64(t0, t0, FP_DRN | FP_ENABLES | FP_RN);
- set_fpr(rD(ctx->opcode), t0);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_FPU(ctx);
- /* Mask FPSCR value to clear RN. */
- tcg_gen_andi_i64(t0, t0, ~FP_RN);
+ t1 = tcg_temp_new_i64();
+ get_fpr(t1, a->rb);
+ tcg_gen_andi_i64(t1, t1, FP_DRN);
- /* Merge RN into FPSCR value. */
- tcg_gen_or_i64(t0, t0, t1);
+ gen_reset_fpstatus();
+ fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
+ store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100);
- gen_helper_store_fpscr(cpu_env, t0, mask);
+ tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(fpscr);
- tcg_temp_free_i32(mask);
- tcg_temp_free_i64(t0);
+ return true;
}
-/* mffscrn */
-static void gen_mffscrn(DisasContext *ctx)
+static bool trans_MFFSCRNI(DisasContext *ctx, arg_X_imm2 *a)
{
- TCGv_i64 t1;
-
- if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
- return gen_mffs(ctx);
- }
+ TCGv_i64 t1, fpscr;
- if (unlikely(!ctx->fpu_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_FPU);
- return;
- }
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_FPU(ctx);
t1 = tcg_temp_new_i64();
- get_fpr(t1, rB(ctx->opcode));
- /* Mask FRB to get just RN. */
- tcg_gen_andi_i64(t1, t1, FP_RN);
+ tcg_gen_movi_i64(t1, a->imm);
- gen_helper_mffscrn(ctx, t1);
+ gen_reset_fpstatus();
+ fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
+ store_fpscr_masked(fpscr, FP_RN, t1, 0x0001);
tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(fpscr);
+
+ return true;
}
-/* mffscrni */
-static void gen_mffscrni(DisasContext *ctx)
+static bool trans_MFFSCDRNI(DisasContext *ctx, arg_X_imm3 *a)
{
- TCGv_i64 t1;
+ TCGv_i64 t1, fpscr;
- if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
- return gen_mffs(ctx);
- }
-
- if (unlikely(!ctx->fpu_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_FPU);
- return;
- }
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_FPU(ctx);
- t1 = tcg_const_i64((uint64_t)RM(ctx->opcode));
+ t1 = tcg_temp_new_i64();
+ tcg_gen_movi_i64(t1, (uint64_t)a->imm << FPSCR_DRN0);
- gen_helper_mffscrn(ctx, t1);
+ gen_reset_fpstatus();
+ fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
+ store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100);
tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(fpscr);
+
+ return true;
+}
+
+static bool trans_MFFSL(DisasContext *ctx, arg_X_t *a)
+{
+ TCGv_i64 fpscr;
+
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_FPU(ctx);
+
+ gen_reset_fpstatus();
+ fpscr = place_from_fpscr(a->rt,
+ FP_DRN | FP_STATUS | FP_ENABLES | FP_NI | FP_RN);
+
+ tcg_temp_free_i64(fpscr);
+
+ return true;
}
/* mtfsb0 */
diff --git a/target/ppc/translate/fp-ops.c.inc b/target/ppc/translate/fp-ops.c.inc
index 0538ab2..1b65f5a 100644
--- a/target/ppc/translate/fp-ops.c.inc
+++ b/target/ppc/translate/fp-ops.c.inc
@@ -74,15 +74,6 @@ GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205),
GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207),
GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207),
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT),
-GEN_HANDLER_E_2(mffs, 0x3F, 0x07, 0x12, 0x00, 0x00000000, PPC_FLOAT, PPC_NONE),
-GEN_HANDLER_E_2(mffsce, 0x3F, 0x07, 0x12, 0x01, 0x00000000, PPC_FLOAT,
- PPC2_ISA300),
-GEN_HANDLER_E_2(mffsl, 0x3F, 0x07, 0x12, 0x18, 0x00000000, PPC_FLOAT,
- PPC2_ISA300),
-GEN_HANDLER_E_2(mffscrn, 0x3F, 0x07, 0x12, 0x16, 0x00000000, PPC_FLOAT,
- PPC_NONE),
-GEN_HANDLER_E_2(mffscrni, 0x3F, 0x07, 0x12, 0x17, 0x00000000, PPC_FLOAT,
- PPC_NONE),
GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT),
diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc
index 0b563be..e644ad3 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -1234,18 +1234,6 @@ GEN_VXFORM_SAT(vsubuws, MO_32, sub, ussub, 0, 26);
GEN_VXFORM_SAT(vsubsbs, MO_8, sub, sssub, 0, 28);
GEN_VXFORM_SAT(vsubshs, MO_16, sub, sssub, 0, 29);
GEN_VXFORM_SAT(vsubsws, MO_32, sub, sssub, 0, 30);
-GEN_VXFORM(vadduqm, 0, 4);
-GEN_VXFORM(vaddcuq, 0, 5);
-GEN_VXFORM3(vaddeuqm, 30, 0);
-GEN_VXFORM3(vaddecuq, 30, 0);
-GEN_VXFORM_DUAL(vaddeuqm, PPC_NONE, PPC2_ALTIVEC_207, \
- vaddecuq, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM(vsubuqm, 0, 20);
-GEN_VXFORM(vsubcuq, 0, 21);
-GEN_VXFORM3(vsubeuqm, 31, 0);
-GEN_VXFORM3(vsubecuq, 31, 0);
-GEN_VXFORM_DUAL(vsubeuqm, PPC_NONE, PPC2_ALTIVEC_207, \
- vsubecuq, PPC_NONE, PPC2_ALTIVEC_207)
GEN_VXFORM_TRANS(vsl, 2, 7);
GEN_VXFORM_TRANS(vsr, 2, 11);
GEN_VXFORM_ENV(vpkuhum, 7, 0);
@@ -2572,6 +2560,12 @@ static bool do_va_helper(DisasContext *ctx, arg_VA *a,
return true;
}
+TRANS_FLAGS2(ALTIVEC_207, VADDECUQ, do_va_helper, gen_helper_VADDECUQ)
+TRANS_FLAGS2(ALTIVEC_207, VADDEUQM, do_va_helper, gen_helper_VADDEUQM)
+
+TRANS_FLAGS2(ALTIVEC_207, VSUBEUQM, do_va_helper, gen_helper_VSUBEUQM)
+TRANS_FLAGS2(ALTIVEC_207, VSUBECUQ, do_va_helper, gen_helper_VSUBECUQ)
+
TRANS_FLAGS(ALTIVEC, VPERM, do_va_helper, gen_helper_VPERM)
TRANS_FLAGS2(ISA300, VPERMR, do_va_helper, gen_helper_VPERMR)
@@ -2717,7 +2711,6 @@ GEN_VXFORM_TRANS(vgbbd, 6, 20);
GEN_VXFORM(vpmsumb, 4, 16)
GEN_VXFORM(vpmsumh, 4, 17)
GEN_VXFORM(vpmsumw, 4, 18)
-GEN_VXFORM(vpmsumd, 4, 19)
#define GEN_BCD(op) \
static void gen_##op(DisasContext *ctx) \
@@ -2862,11 +2855,6 @@ GEN_VXFORM_DUAL(vsubuwm, PPC_ALTIVEC, PPC_NONE, \
bcdus, PPC_NONE, PPC2_ISA300)
GEN_VXFORM_DUAL(vsubsbs, PPC_ALTIVEC, PPC_NONE, \
bcdtrunc, PPC_NONE, PPC2_ISA300)
-GEN_VXFORM_DUAL(vsubuqm, PPC2_ALTIVEC_207, PPC_NONE, \
- bcdtrunc, PPC_NONE, PPC2_ISA300)
-GEN_VXFORM_DUAL(vsubcuq, PPC2_ALTIVEC_207, PPC_NONE, \
- bcdutrunc, PPC_NONE, PPC2_ISA300)
-
static void gen_vsbox(DisasContext *ctx)
{
@@ -3101,6 +3089,14 @@ static bool do_vx_helper(DisasContext *ctx, arg_VX *a,
return true;
}
+TRANS_FLAGS2(ALTIVEC_207, VADDCUQ, do_vx_helper, gen_helper_VADDCUQ)
+TRANS_FLAGS2(ALTIVEC_207, VADDUQM, do_vx_helper, gen_helper_VADDUQM)
+
+TRANS_FLAGS2(ALTIVEC_207, VPMSUMD, do_vx_helper, gen_helper_VPMSUMD)
+
+TRANS_FLAGS2(ALTIVEC_207, VSUBCUQ, do_vx_helper, gen_helper_VSUBCUQ)
+TRANS_FLAGS2(ALTIVEC_207, VSUBUQM, do_vx_helper, gen_helper_VSUBUQM)
+
static bool do_vx_vmuleo(DisasContext *ctx, arg_VX *a, bool even,
void (*gen_mul)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
{
diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc
index d7cc578..a3a0fd0 100644
--- a/target/ppc/translate/vmx-ops.c.inc
+++ b/target/ppc/translate/vmx-ops.c.inc
@@ -126,12 +126,8 @@ GEN_VXFORM(vsubuws, 0, 26),
GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_ALTIVEC, PPC2_ISA300),
GEN_VXFORM(vsubshs, 0, 29),
GEN_VXFORM_DUAL(vsubsws, xpnd04_2, 0, 30, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM_207(vadduqm, 0, 4),
-GEN_VXFORM_207(vaddcuq, 0, 5),
-GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
-GEN_VXFORM_DUAL(vsubuqm, bcdtrunc, 0, 20, PPC2_ALTIVEC_207, PPC2_ISA300),
-GEN_VXFORM_DUAL(vsubcuq, bcdutrunc, 0, 21, PPC2_ALTIVEC_207, PPC2_ISA300),
-GEN_VXFORM_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_300(bcdtrunc, 0, 20),
+GEN_VXFORM_300(bcdutrunc, 0, 21),
GEN_VXFORM(vsl, 2, 7),
GEN_VXFORM(vsr, 2, 11),
GEN_VXFORM(vpkuhum, 7, 0),
@@ -237,7 +233,6 @@ GEN_VXFORM_207(vgbbd, 6, 20),
GEN_VXFORM_207(vpmsumb, 4, 16),
GEN_VXFORM_207(vpmsumh, 4, 17),
GEN_VXFORM_207(vpmsumw, 4, 18),
-GEN_VXFORM_207(vpmsumd, 4, 19),
GEN_VXFORM_207(vsbox, 4, 23),
diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target
index babd209..331fae6 100644
--- a/tests/tcg/ppc64/Makefile.target
+++ b/tests/tcg/ppc64/Makefile.target
@@ -11,6 +11,7 @@ endif
$(PPC64_TESTS): CFLAGS += -mpower8-vector
PPC64_TESTS += mtfsf
+PPC64_TESTS += mffsce
ifneq ($(CROSS_CC_HAS_POWER10),)
PPC64_TESTS += byte_reverse sha512-vector
diff --git a/tests/tcg/ppc64le/Makefile.target b/tests/tcg/ppc64le/Makefile.target
index 5b0eb5e..6ca3003 100644
--- a/tests/tcg/ppc64le/Makefile.target
+++ b/tests/tcg/ppc64le/Makefile.target
@@ -24,6 +24,7 @@ run-sha512-vector: QEMU_OPTS+=-cpu POWER10
run-plugin-sha512-vector-with-%: QEMU_OPTS+=-cpu POWER10
PPC64LE_TESTS += mtfsf
+PPC64LE_TESTS += mffsce
PPC64LE_TESTS += signal_save_restore_xer
PPC64LE_TESTS += xxspltw
diff --git a/tests/tcg/ppc64le/mffsce.c b/tests/tcg/ppc64le/mffsce.c
new file mode 100644
index 0000000..20d882c
--- /dev/null
+++ b/tests/tcg/ppc64le/mffsce.c
@@ -0,0 +1,37 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+
+#define MTFSF(FLM, FRB) asm volatile ("mtfsf %0, %1" :: "i" (FLM), "f" (FRB))
+#define MFFS(FRT) asm("mffs %0" : "=f" (FRT))
+#define MFFSCE(FRT) asm("mffsce %0" : "=f" (FRT))
+
+#define PPC_BIT_NR(nr) (63 - (nr))
+
+#define FP_VE (1ull << PPC_BIT_NR(56))
+#define FP_UE (1ull << PPC_BIT_NR(58))
+#define FP_ZE (1ull << PPC_BIT_NR(59))
+#define FP_XE (1ull << PPC_BIT_NR(60))
+#define FP_NI (1ull << PPC_BIT_NR(61))
+#define FP_RN1 (1ull << PPC_BIT_NR(63))
+
+int main(void)
+{
+ uint64_t frt, fpscr;
+ uint64_t test_value = FP_VE | FP_UE | FP_ZE |
+ FP_XE | FP_NI | FP_RN1;
+ MTFSF(0b11111111, test_value); /* set test value to cpu fpscr */
+ MFFSCE(frt);
+ MFFS(fpscr); /* read the value that mffsce stored to cpu fpscr */
+
+ /* the returned value should be as the cpu fpscr was before */
+ assert((frt & 0xff) == test_value);
+
+ /*
+ * the cpu fpscr last 3 bits should be unchanged
+ * and enable bits should be unset
+ */
+ assert((fpscr & 0xff) == (test_value & 0x7));
+
+ return 0;
+}