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

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>
This commit is contained in:
Richard Henderson 2022-07-07 06:21:05 +05:30
commit 8e9398e3b1
33 changed files with 912 additions and 603 deletions

View File

@ -66,26 +66,6 @@ static const XiveVstInfo vst_infos[] = {
qemu_log_mask(LOG_GUEST_ERROR, "XIVE[%x] - " fmt "\n", \
(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

View File

@ -75,26 +75,6 @@ static const XiveVstInfo vst_infos[] = {
qemu_log_mask(LOG_GUEST_ERROR, "XIVE[%x] - " fmt "\n", \
(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
*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,22 +12,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
*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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];
Int128 tmp, prod[2] = {int128_zero(), int128_zero()};
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);
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->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);
}
}
}
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)
void helper_VADDUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
t->u64[0] = ~a.u64[0];
t->u64[1] = ~a.u64[1];
r->s128 = int128_add(a->s128, b->s128);
}
static int avr_qw_cmpu(ppc_avr_t a, ppc_avr_t b)
void helper_VADDEUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
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;
}
r->s128 = int128_add(int128_add(a->s128, b->s128),
int128_make64(int128_getlo(c->s128) & 1));
}
static void avr_qw_add(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
void helper_VADDCUQ(ppc_avr_t *r, 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)
{
#ifdef CONFIG_INT128
r->u128 = a->u128 + b->u128;
#else
avr_qw_add(r, *a, *b);
#endif
}
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
}
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);
}
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)
{
#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
}
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
}
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));
}
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)
{
#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));
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)
{
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)
{
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)
{
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;
}
void helper_VSUBECUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
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;
}
#define BCD_PLUS_PREF_1 0xC

View File

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

View File

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

View File

@ -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);
}
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);
}
/* mffsce */
static void gen_mffsce(DisasContext *ctx)
{
TCGv_i64 t0;
TCGv_i32 mask;
if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
return gen_mffs(ctx);
}
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
t0 = tcg_temp_new_i64();
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
REQUIRE_FPU(ctx);
gen_reset_fpstatus();
tcg_gen_extu_tl_i64(t0, cpu_fpscr);
set_fpr(rD(ctx->opcode), t0);
fpscr = place_from_fpscr(a->rt, UINT64_MAX);
store_fpscr_masked(fpscr, FP_ENABLES, tcg_constant_i64(0), 0x0003);
/* 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(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_MFFSCRN(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);
/* Mask FPSCR value to clear RN. */
tcg_gen_andi_i64(t0, t0, ~FP_RN);
/* Merge RN into FPSCR value. */
tcg_gen_or_i64(t0, t0, t1);
gen_helper_store_fpscr(cpu_env, t0, mask);
tcg_temp_free_i32(mask);
tcg_temp_free_i64(t0);
}
/* mffscrn */
static void gen_mffscrn(DisasContext *ctx)
{
TCGv_i64 t1;
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_temp_new_i64();
get_fpr(t1, rB(ctx->opcode));
/* Mask FRB to get just RN. */
get_fpr(t1, a->rb);
tcg_gen_andi_i64(t1, t1, FP_RN);
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_MFFSCDRN(DisasContext *ctx, arg_X_tb *a)
{
TCGv_i64 t1;
TCGv_i64 t1, 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;
}
t1 = tcg_temp_new_i64();
get_fpr(t1, a->rb);
tcg_gen_andi_i64(t1, t1, FP_DRN);
t1 = tcg_const_i64((uint64_t)RM(ctx->opcode));
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_MFFSCRNI(DisasContext *ctx, arg_X_imm2 *a)
{
TCGv_i64 t1, fpscr;
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
REQUIRE_FPU(ctx);
t1 = tcg_temp_new_i64();
tcg_gen_movi_i64(t1, a->imm);
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;
}
static bool trans_MFFSCDRNI(DisasContext *ctx, arg_X_imm3 *a)
{
TCGv_i64 t1, fpscr;
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
REQUIRE_FPU(ctx);
t1 = tcg_temp_new_i64();
tcg_gen_movi_i64(t1, (uint64_t)a->imm << FPSCR_DRN0);
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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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