mirror of
https://github.com/xemu-project/xemu.git
synced 2026-07-11 01:24:41 +02:00
Merge tag 'pull-ppc-for-20250928-20250929' of https://gitlab.com/harshpb/qemu into staging
ppc queue for 20250928 * Support for PowerNV11 and PPE42 CPU/Machines. * Deprecation of Power8E and Power8NVL * Decodetree patches for some floating-point instructions * Minor bug fixes, improvements in ppc/spapr/xive/xics. # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEEa4EM1tK+EPOIPSFCRUTplPnWj7sFAmjZgYQACgkQRUTplPnW # j7uNJQ/8Cbr3xqyCyyqL+MM+Ze1PbXe4xSgdg13A1sNU3IHTffB77DCQVOxjudUS # uo+XHVFssc4SKDZYjEzXFnYpzRpbZzfcuhG4kgn9QQ3VyKP+2xe6kWLleDbB6ds1 # e9ZAW6Ryk4R3ZFLnZzGfEdltliaoIn6zy4R25oJfJUgIRt0Xz++GBxll+Tdr8Exy # qstvvyyjeTiIS3kA1zk6fbhDRJKKBsA0L1G1Pk6AuTMKa1RRTCniA36idnGVFAuY # ef8WCEQYQS0do9Ytai06Tp1QNRVMG2y+AsKbSQRMi92lFfn+qhvA29OJd5TNvXtp # LNiIfXHo3jLjGBUP13iVN8b8udWdis9BayvA/OwDaKWgononEHb9nqJgzVJR4n7t # DxxUxcSCiEXOpObtklrKhi1nDt16nXPZ/bnnreMSWzxHBZK1My7qnI3S0hA7c11z # YgssB5wJbRaETaEVzQfWfAcSaPpXBzBEXOAJcbd+Ni6w9SxXz2OrhckTOvfrXpmI # XQ1KFUCkmTtXF1qB+oEihlrvG2qjdGuleRZdyiktaM2psBFgN/2gHl3S+JjL9kiY # 9FdBffr/2K604l7EQkAYWixe2WMMsjHVHpuxJ7opG7MMSXJZq9cXKIK+tbkSNoRO # Ia6Qr6eWJWjFF3y4OZCbYAOVU77ez6lo7kRj0e99fOjxfI+UuWU= # =Fjdq # -----END PGP SIGNATURE----- # gpg: Signature made Sun 28 Sep 2025 11:42:12 AM PDT # gpg: using RSA key 6B810CD6D2BE10F3883D21424544E994F9D68FBB # gpg: Good signature from "Harsh Prateek Bora <harsh.prateek.bora@gmail.com>" [undefined] # gpg: aka "Harsh Prateek Bora <harshpb@linux.ibm.com>" [undefined] # 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: 6B81 0CD6 D2BE 10F3 883D 2142 4544 E994 F9D6 8FBB * tag 'pull-ppc-for-20250928-20250929' of https://gitlab.com/harshpb/qemu: (27 commits) target/ppc: use MAKE_64BIT_MASK for mcrfs exception clear mask target/ppc: Deprecate Power8E and Power8NVL target/ppc: Introduce macro for deprecating PowerPC CPUs target/ppc: Move remaining floating-point move instructions to decodetree. target/ppc: Move floating-point move instructions to decodetree. target/ppc: Move floating-point compare instructions to decodetree. target/ppc: Move floating-point rounding and conversion instructions to decodetree. ppc/xive2: Fix integer overflow warning in xive2_redistribute() ppc/spapr: init lrdr-capapcity phys with ram size if maxmem not provided hw/intc/xics: Add missing call to register vmstate_icp_server tests/functional: Add test for IBM PPE42 instructions hw/ppc: Add a test machine for the IBM PPE42 CPU hw/ppc: Support for an IBM PPE42 CPU decrementer target/ppc: Add IBM PPE42 special instructions target/ppc: Support for IBM PPE42 MMU target/ppc: Add IBM PPE42 exception model target/ppc: IBM PPE42 exception flags and regs target/ppc: Add IBM PPE42 family of processors target/ppc: IBM PPE42 general regs and flags tests/powernv: Add PowerNV test for Power11 ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
@@ -1530,6 +1530,13 @@ F: include/hw/pci-host/grackle.h
|
||||
F: pc-bios/qemu_vga.ndrv
|
||||
F: tests/functional/ppc/test_mac.py
|
||||
|
||||
PPE42
|
||||
M: Glenn Miles <milesg@linux.ibm.com>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/ppc/ppe42_machine.c
|
||||
F: tests/functional/ppc/test_ppe42.py
|
||||
|
||||
PReP
|
||||
M: Hervé Poussineau <hpoussin@reactos.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
|
||||
@@ -253,6 +253,15 @@ embedded 405 for power management (OCC) and other internal tasks, it
|
||||
is theoretically possible to use QEMU to model them. Let's keep the
|
||||
CPU implementation for a while before removing all support.
|
||||
|
||||
Power8E and Power8NVL CPUs and corresponding Pnv chips (since 10.1)
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The Power8E and Power8NVL variants of Power8 are not really useful anymore
|
||||
in qemu, and are old and unmaintained now.
|
||||
|
||||
The CPUs as well as corresponding Power8NVL and Power8E PnvChips will also
|
||||
be considered deprecated.
|
||||
|
||||
System emulator machines
|
||||
------------------------
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
PowerNV family boards (``powernv8``, ``powernv9``, ``powernv10``)
|
||||
==================================================================
|
||||
PowerNV family boards (``powernv8``, ``powernv9``, ``powernv10``, ``powernv11``)
|
||||
================================================================================
|
||||
|
||||
PowerNV (as Non-Virtualized) is the "bare metal" platform using the
|
||||
OPAL firmware. It runs Linux on IBM and OpenPOWER systems and it can
|
||||
@@ -15,11 +15,12 @@ beyond the scope of what QEMU addresses today.
|
||||
Supported devices
|
||||
-----------------
|
||||
|
||||
* Multi processor support for POWER8, POWER8NVL and POWER9.
|
||||
* Multi processor support for POWER8, POWER8NVL, POWER9, Power10 and Power11.
|
||||
* XSCOM, serial communication sideband bus to configure chiplets.
|
||||
* Simple LPC Controller.
|
||||
* Processor Service Interface (PSI) Controller.
|
||||
* Interrupt Controller, XICS (POWER8) and XIVE (POWER9) and XIVE2 (Power10).
|
||||
* Interrupt Controller, XICS (POWER8) and XIVE (POWER9) and XIVE2 (Power10 &
|
||||
Power11).
|
||||
* POWER8 PHB3 PCIe Host bridge and POWER9 PHB4 PCIe Host bridge.
|
||||
* Simple OCC is an on-chip micro-controller used for power management tasks.
|
||||
* iBT device to handle BMC communication, with the internal BMC simulator
|
||||
|
||||
+2
-2
@@ -110,8 +110,8 @@ static PnvXive2 *pnv_xive2_get_remote(uint32_t vsd_type, hwaddr fwd_addr)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pnv->num_chips; i++) {
|
||||
Pnv10Chip *chip10 = PNV10_CHIP(pnv->chips[i]);
|
||||
PnvXive2 *xive = &chip10->xive;
|
||||
PnvChipClass *k = PNV_CHIP_GET_CLASS(pnv->chips[i]);
|
||||
PnvXive2 *xive = PNV_XIVE2(k->intc_get(pnv->chips[i]));
|
||||
|
||||
/*
|
||||
* Is this the XIVE matching the forwarded VSD address is for this
|
||||
|
||||
@@ -335,6 +335,8 @@ static void icp_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vmstate_register(NULL, icp->cs->cpu_index, &vmstate_icp_server, icp);
|
||||
}
|
||||
|
||||
static void icp_unrealize(DeviceState *dev)
|
||||
|
||||
+31
-14
@@ -95,6 +95,35 @@ static void xive2_nvgc_set_backlog(Xive2Nvgc *nvgc, uint8_t priority,
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t xive2_nvgc_get_idx(uint32_t nvp_idx, uint8_t group)
|
||||
{
|
||||
uint32_t nvgc_idx;
|
||||
|
||||
if (group > 0) {
|
||||
nvgc_idx = (nvp_idx & (0xffffffffULL << group)) |
|
||||
((1 << (group - 1)) - 1);
|
||||
} else {
|
||||
nvgc_idx = nvp_idx;
|
||||
}
|
||||
|
||||
return nvgc_idx;
|
||||
}
|
||||
|
||||
static uint8_t xive2_nvgc_get_blk(uint8_t nvp_blk, uint8_t crowd)
|
||||
{
|
||||
uint8_t nvgc_blk;
|
||||
|
||||
if (crowd > 0) {
|
||||
crowd = (crowd == 3) ? 4 : crowd;
|
||||
nvgc_blk = (nvp_blk & (0xffffffffULL << crowd)) |
|
||||
((1 << (crowd - 1)) - 1);
|
||||
} else {
|
||||
nvgc_blk = nvp_blk;
|
||||
}
|
||||
|
||||
return nvgc_blk;
|
||||
}
|
||||
|
||||
uint64_t xive2_presenter_nvgc_backlog_op(XivePresenter *xptr,
|
||||
bool crowd,
|
||||
uint8_t blk, uint32_t idx,
|
||||
@@ -638,20 +667,8 @@ static void xive2_redistribute(Xive2Router *xrtr, XiveTCTX *tctx, uint8_t ring)
|
||||
|
||||
trace_xive_redistribute(tctx->cs->cpu_index, ring, nvp_blk, nvp_idx);
|
||||
/* convert crowd/group to blk/idx */
|
||||
if (group > 0) {
|
||||
nvgc_idx = (nvp_idx & (0xffffffff << group)) |
|
||||
((1 << (group - 1)) - 1);
|
||||
} else {
|
||||
nvgc_idx = nvp_idx;
|
||||
}
|
||||
|
||||
if (crowd > 0) {
|
||||
crowd = (crowd == 3) ? 4 : crowd;
|
||||
nvgc_blk = (nvp_blk & (0xffffffff << crowd)) |
|
||||
((1 << (crowd - 1)) - 1);
|
||||
} else {
|
||||
nvgc_blk = nvp_blk;
|
||||
}
|
||||
nvgc_idx = xive2_nvgc_get_idx(nvp_idx, group);
|
||||
nvgc_blk = xive2_nvgc_get_blk(nvp_blk, crowd);
|
||||
|
||||
/* Use blk/idx to retrieve the NVGC */
|
||||
if (xive2_router_get_nvgc(xrtr, crowd, nvgc_blk, nvgc_idx, &nvgc)) {
|
||||
|
||||
@@ -44,6 +44,11 @@ config POWERNV
|
||||
select SSI_M25P80
|
||||
select PNV_SPI
|
||||
|
||||
config PPC405
|
||||
bool
|
||||
default y
|
||||
depends on PPC
|
||||
|
||||
config PPC440
|
||||
bool
|
||||
default y
|
||||
|
||||
@@ -57,6 +57,8 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
|
||||
'pnv_n1_chiplet.c',
|
||||
))
|
||||
# PowerPC 4xx boards
|
||||
ppc_ss.add(when: 'CONFIG_PPC405', if_true: files(
|
||||
'ppe42_machine.c'))
|
||||
ppc_ss.add(when: 'CONFIG_PPC440', if_true: files(
|
||||
'ppc440_bamboo.c',
|
||||
'ppc440_uc.c'))
|
||||
|
||||
+560
@@ -491,6 +491,37 @@ static void pnv_chip_power10_dt_populate(PnvChip *chip, void *fdt)
|
||||
pnv_dt_lpc(chip, fdt, 0, PNV10_LPCM_BASE(chip), PNV10_LPCM_SIZE);
|
||||
}
|
||||
|
||||
static void pnv_chip_power11_dt_populate(PnvChip *chip, void *fdt)
|
||||
{
|
||||
static const char compat[] = "ibm,power11-xscom\0ibm,xscom";
|
||||
int i;
|
||||
|
||||
pnv_dt_xscom(chip, fdt, 0,
|
||||
cpu_to_be64(PNV11_XSCOM_BASE(chip)),
|
||||
cpu_to_be64(PNV11_XSCOM_SIZE),
|
||||
compat, sizeof(compat));
|
||||
|
||||
for (i = 0; i < chip->nr_cores; i++) {
|
||||
PnvCore *pnv_core = chip->cores[i];
|
||||
int offset;
|
||||
|
||||
offset = pnv_dt_core(chip, pnv_core, fdt);
|
||||
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
|
||||
pa_features_31, sizeof(pa_features_31))));
|
||||
|
||||
if (pnv_core->big_core) {
|
||||
i++; /* Big-core groups two QEMU cores */
|
||||
}
|
||||
}
|
||||
|
||||
if (chip->ram_size) {
|
||||
pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
|
||||
}
|
||||
|
||||
pnv_dt_lpc(chip, fdt, 0, PNV11_LPCM_BASE(chip), PNV11_LPCM_SIZE);
|
||||
}
|
||||
|
||||
static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
|
||||
{
|
||||
uint32_t io_base = d->ioport_id;
|
||||
@@ -823,6 +854,26 @@ static ISABus *pnv_chip_power10_isa_create(PnvChip *chip, Error **errp)
|
||||
return pnv_lpc_isa_create(&chip10->lpc, false, errp);
|
||||
}
|
||||
|
||||
static ISABus *pnv_chip_power11_isa_create(PnvChip *chip, Error **errp)
|
||||
{
|
||||
Pnv11Chip *chip11 = PNV11_CHIP(chip);
|
||||
qemu_irq irq;
|
||||
|
||||
irq = qdev_get_gpio_in(DEVICE(&chip11->psi), PSIHB9_IRQ_LPCHC);
|
||||
qdev_connect_gpio_out_named(DEVICE(&chip11->lpc), "LPCHC", 0, irq);
|
||||
|
||||
irq = qdev_get_gpio_in(DEVICE(&chip11->psi), PSIHB9_IRQ_LPC_SIRQ0);
|
||||
qdev_connect_gpio_out_named(DEVICE(&chip11->lpc), "SERIRQ", 0, irq);
|
||||
irq = qdev_get_gpio_in(DEVICE(&chip11->psi), PSIHB9_IRQ_LPC_SIRQ1);
|
||||
qdev_connect_gpio_out_named(DEVICE(&chip11->lpc), "SERIRQ", 1, irq);
|
||||
irq = qdev_get_gpio_in(DEVICE(&chip11->psi), PSIHB9_IRQ_LPC_SIRQ2);
|
||||
qdev_connect_gpio_out_named(DEVICE(&chip11->lpc), "SERIRQ", 2, irq);
|
||||
irq = qdev_get_gpio_in(DEVICE(&chip11->psi), PSIHB9_IRQ_LPC_SIRQ3);
|
||||
qdev_connect_gpio_out_named(DEVICE(&chip11->lpc), "SERIRQ", 3, irq);
|
||||
|
||||
return pnv_lpc_isa_create(&chip11->lpc, false, errp);
|
||||
}
|
||||
|
||||
static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
|
||||
{
|
||||
return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
|
||||
@@ -886,6 +937,12 @@ static uint64_t pnv_chip_power10_xscom_core_base(PnvChip *chip,
|
||||
return PNV10_XSCOM_EC_BASE(core_id);
|
||||
}
|
||||
|
||||
static uint64_t pnv_chip_power11_xscom_core_base(PnvChip *chip,
|
||||
uint32_t core_id)
|
||||
{
|
||||
return PNV11_XSCOM_EC_BASE(core_id);
|
||||
}
|
||||
|
||||
static bool pnv_match_cpu(const char *default_type, const char *cpu_type)
|
||||
{
|
||||
PowerPCCPUClass *ppc_default =
|
||||
@@ -915,6 +972,16 @@ static void pnv_chip_power10_pic_print_info(PnvChip *chip, GString *buf)
|
||||
pnv_chip_power9_pic_print_info_child, buf);
|
||||
}
|
||||
|
||||
static void pnv_chip_power11_pic_print_info(PnvChip *chip, GString *buf)
|
||||
{
|
||||
Pnv11Chip *chip11 = PNV11_CHIP(chip);
|
||||
|
||||
pnv_xive2_pic_print_info(&chip11->xive, buf);
|
||||
pnv_psi_pic_print_info(&chip11->psi, buf);
|
||||
object_child_foreach_recursive(OBJECT(chip),
|
||||
pnv_chip_power9_pic_print_info_child, buf);
|
||||
}
|
||||
|
||||
/* Always give the first 1GB to chip 0 else we won't boot */
|
||||
static uint64_t pnv_chip_get_ram_size(PnvMachineState *pnv, int chip_id)
|
||||
{
|
||||
@@ -1422,6 +1489,60 @@ static void pnv_chip_power10_intc_print_info(PnvChip *chip, PowerPCCPU *cpu,
|
||||
xive_tctx_pic_print_info(XIVE_TCTX(pnv_cpu_state(cpu)->intc), buf);
|
||||
}
|
||||
|
||||
static void *pnv_chip_power10_intc_get(PnvChip *chip)
|
||||
{
|
||||
return &PNV10_CHIP(chip)->xive;
|
||||
}
|
||||
|
||||
static void pnv_chip_power11_intc_create(PnvChip *chip, PowerPCCPU *cpu,
|
||||
Error **errp)
|
||||
{
|
||||
Pnv11Chip *chip11 = PNV11_CHIP(chip);
|
||||
Error *local_err = NULL;
|
||||
Object *obj;
|
||||
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
|
||||
|
||||
/*
|
||||
* The core creates its interrupt presenter but the XIVE2 interrupt
|
||||
* controller object is initialized afterwards. Hopefully, it's
|
||||
* only used at runtime.
|
||||
*/
|
||||
obj = xive_tctx_create(OBJECT(cpu), XIVE_PRESENTER(&chip11->xive),
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
pnv_cpu->intc = obj;
|
||||
}
|
||||
|
||||
static void pnv_chip_power11_intc_reset(PnvChip *chip, PowerPCCPU *cpu)
|
||||
{
|
||||
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
|
||||
|
||||
xive_tctx_reset(XIVE_TCTX(pnv_cpu->intc));
|
||||
}
|
||||
|
||||
static void pnv_chip_power11_intc_destroy(PnvChip *chip, PowerPCCPU *cpu)
|
||||
{
|
||||
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
|
||||
|
||||
xive_tctx_destroy(XIVE_TCTX(pnv_cpu->intc));
|
||||
pnv_cpu->intc = NULL;
|
||||
}
|
||||
|
||||
static void pnv_chip_power11_intc_print_info(PnvChip *chip, PowerPCCPU *cpu,
|
||||
GString *buf)
|
||||
{
|
||||
xive_tctx_pic_print_info(XIVE_TCTX(pnv_cpu_state(cpu)->intc), buf);
|
||||
}
|
||||
|
||||
static void *pnv_chip_power11_intc_get(PnvChip *chip)
|
||||
{
|
||||
return &PNV11_CHIP(chip)->xive;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allowed core identifiers on a POWER8 Processor Chip :
|
||||
*
|
||||
@@ -1452,6 +1573,8 @@ static void pnv_chip_power10_intc_print_info(PnvChip *chip, PowerPCCPU *cpu,
|
||||
|
||||
#define POWER10_CORE_MASK (0xffffffffffffffull)
|
||||
|
||||
#define POWER11_CORE_MASK (0xffffffffffffffull)
|
||||
|
||||
static void pnv_chip_power8_instance_init(Object *obj)
|
||||
{
|
||||
Pnv8Chip *chip8 = PNV8_CHIP(obj);
|
||||
@@ -2350,6 +2473,302 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static void pnv_chip_power11_instance_init(Object *obj)
|
||||
{
|
||||
PnvChip *chip = PNV_CHIP(obj);
|
||||
Pnv11Chip *chip11 = PNV11_CHIP(obj);
|
||||
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj);
|
||||
int i;
|
||||
|
||||
object_initialize_child(obj, "adu", &chip11->adu, TYPE_PNV_ADU);
|
||||
|
||||
/*
|
||||
* Use Power10 device models for PSI/LPC/OCC/SBE/HOMER as corresponding
|
||||
* device models for Power11 are same
|
||||
*/
|
||||
object_initialize_child(obj, "psi", &chip11->psi, TYPE_PNV10_PSI);
|
||||
object_initialize_child(obj, "lpc", &chip11->lpc, TYPE_PNV10_LPC);
|
||||
object_initialize_child(obj, "occ", &chip11->occ, TYPE_PNV10_OCC);
|
||||
object_initialize_child(obj, "sbe", &chip11->sbe, TYPE_PNV10_SBE);
|
||||
object_initialize_child(obj, "homer", &chip11->homer, TYPE_PNV10_HOMER);
|
||||
|
||||
object_initialize_child(obj, "xive", &chip11->xive, TYPE_PNV_XIVE2);
|
||||
object_property_add_alias(obj, "xive-fabric", OBJECT(&chip11->xive),
|
||||
"xive-fabric");
|
||||
object_initialize_child(obj, "chiptod", &chip11->chiptod,
|
||||
TYPE_PNV11_CHIPTOD);
|
||||
object_initialize_child(obj, "n1-chiplet", &chip11->n1_chiplet,
|
||||
TYPE_PNV_N1_CHIPLET);
|
||||
|
||||
chip->num_pecs = pcc->num_pecs;
|
||||
|
||||
for (i = 0; i < chip->num_pecs; i++) {
|
||||
object_initialize_child(obj, "pec[*]", &chip11->pecs[i],
|
||||
TYPE_PNV_PHB5_PEC);
|
||||
}
|
||||
|
||||
for (i = 0; i < pcc->i2c_num_engines; i++) {
|
||||
object_initialize_child(obj, "i2c[*]", &chip11->i2c[i], TYPE_PNV_I2C);
|
||||
}
|
||||
|
||||
for (i = 0; i < PNV10_CHIP_MAX_PIB_SPIC; i++) {
|
||||
object_initialize_child(obj, "pib_spic[*]", &chip11->pib_spic[i],
|
||||
TYPE_PNV_SPI);
|
||||
}
|
||||
}
|
||||
|
||||
static void pnv_chip_power11_quad_realize(Pnv11Chip *chip11, Error **errp)
|
||||
{
|
||||
PnvChip *chip = PNV_CHIP(chip11);
|
||||
int i;
|
||||
|
||||
chip11->nr_quads = DIV_ROUND_UP(chip->nr_cores, 4);
|
||||
chip11->quads = g_new0(PnvQuad, chip11->nr_quads);
|
||||
|
||||
for (i = 0; i < chip11->nr_quads; i++) {
|
||||
PnvQuad *eq = &chip11->quads[i];
|
||||
|
||||
pnv_chip_quad_realize_one(chip, eq, chip->cores[i * 4],
|
||||
PNV_QUAD_TYPE_NAME("power11"));
|
||||
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_EQ_BASE(eq->quad_id),
|
||||
&eq->xscom_regs);
|
||||
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_QME_BASE(eq->quad_id),
|
||||
&eq->xscom_qme_regs);
|
||||
}
|
||||
}
|
||||
|
||||
static void pnv_chip_power11_phb_realize(PnvChip *chip, Error **errp)
|
||||
{
|
||||
Pnv11Chip *chip11 = PNV11_CHIP(chip);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < chip->num_pecs; i++) {
|
||||
PnvPhb4PecState *pec = &chip11->pecs[i];
|
||||
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
|
||||
uint32_t pec_cplt_base;
|
||||
uint32_t pec_nest_base;
|
||||
uint32_t pec_pci_base;
|
||||
|
||||
object_property_set_int(OBJECT(pec), "index", i, &error_fatal);
|
||||
object_property_set_int(OBJECT(pec), "chip-id", chip->chip_id,
|
||||
&error_fatal);
|
||||
object_property_set_link(OBJECT(pec), "chip", OBJECT(chip),
|
||||
&error_fatal);
|
||||
if (!qdev_realize(DEVICE(pec), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
pec_cplt_base = pecc->xscom_cplt_base(pec);
|
||||
pec_nest_base = pecc->xscom_nest_base(pec);
|
||||
pec_pci_base = pecc->xscom_pci_base(pec);
|
||||
|
||||
pnv_xscom_add_subregion(chip, pec_cplt_base,
|
||||
&pec->nest_pervasive.xscom_ctrl_regs_mr);
|
||||
pnv_xscom_add_subregion(chip, pec_nest_base, &pec->nest_regs_mr);
|
||||
pnv_xscom_add_subregion(chip, pec_pci_base, &pec->pci_regs_mr);
|
||||
}
|
||||
}
|
||||
|
||||
static void pnv_chip_power11_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
|
||||
PnvChip *chip = PNV_CHIP(dev);
|
||||
Pnv11Chip *chip11 = PNV11_CHIP(dev);
|
||||
PowerPCCPU *cpu;
|
||||
PowerPCCPUClass *cpu_class;
|
||||
Error *local_err = NULL;
|
||||
int i;
|
||||
|
||||
/* XSCOM bridge is first */
|
||||
pnv_xscom_init(chip, PNV11_XSCOM_SIZE, PNV11_XSCOM_BASE(chip));
|
||||
|
||||
pcc->parent_realize(dev, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set handlers for Special registers, such as SPRD */
|
||||
cpu = chip->cores[0]->threads[0];
|
||||
cpu_class = POWERPC_CPU_GET_CLASS(cpu);
|
||||
cpu_class->load_sprd = pnv_handle_sprd_load;
|
||||
cpu_class->store_sprd = pnv_handle_sprd_store;
|
||||
|
||||
/* ADU */
|
||||
object_property_set_link(OBJECT(&chip11->adu), "lpc", OBJECT(&chip11->lpc),
|
||||
&error_abort);
|
||||
if (!qdev_realize(DEVICE(&chip11->adu), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_ADU_BASE,
|
||||
&chip11->adu.xscom_regs);
|
||||
|
||||
pnv_chip_power11_quad_realize(chip11, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* XIVE2 interrupt controller */
|
||||
object_property_set_int(OBJECT(&chip11->xive), "ic-bar",
|
||||
PNV11_XIVE2_IC_BASE(chip), &error_fatal);
|
||||
object_property_set_int(OBJECT(&chip11->xive), "esb-bar",
|
||||
PNV11_XIVE2_ESB_BASE(chip), &error_fatal);
|
||||
object_property_set_int(OBJECT(&chip11->xive), "end-bar",
|
||||
PNV11_XIVE2_END_BASE(chip), &error_fatal);
|
||||
object_property_set_int(OBJECT(&chip11->xive), "nvpg-bar",
|
||||
PNV11_XIVE2_NVPG_BASE(chip), &error_fatal);
|
||||
object_property_set_int(OBJECT(&chip11->xive), "nvc-bar",
|
||||
PNV11_XIVE2_NVC_BASE(chip), &error_fatal);
|
||||
object_property_set_int(OBJECT(&chip11->xive), "tm-bar",
|
||||
PNV11_XIVE2_TM_BASE(chip), &error_fatal);
|
||||
object_property_set_link(OBJECT(&chip11->xive), "chip", OBJECT(chip),
|
||||
&error_abort);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&chip11->xive), errp)) {
|
||||
return;
|
||||
}
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_XIVE2_BASE,
|
||||
&chip11->xive.xscom_regs);
|
||||
|
||||
/* Processor Service Interface (PSI) Host Bridge */
|
||||
object_property_set_int(OBJECT(&chip11->psi), "bar",
|
||||
PNV11_PSIHB_BASE(chip), &error_fatal);
|
||||
/* PSI can be configured to use 64k ESB pages on Power11 */
|
||||
object_property_set_int(OBJECT(&chip11->psi), "shift", XIVE_ESB_64K,
|
||||
&error_fatal);
|
||||
if (!qdev_realize(DEVICE(&chip11->psi), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_PSIHB_BASE,
|
||||
&PNV_PSI(&chip11->psi)->xscom_regs);
|
||||
|
||||
/* LPC */
|
||||
if (!qdev_realize(DEVICE(&chip11->lpc), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), PNV11_LPCM_BASE(chip),
|
||||
&chip11->lpc.xscom_regs);
|
||||
|
||||
chip->fw_mr = &chip11->lpc.isa_fw;
|
||||
chip->dt_isa_nodename = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
|
||||
(uint64_t) PNV11_LPCM_BASE(chip));
|
||||
|
||||
/* ChipTOD */
|
||||
object_property_set_bool(OBJECT(&chip11->chiptod), "primary",
|
||||
chip->chip_id == 0, &error_abort);
|
||||
object_property_set_bool(OBJECT(&chip11->chiptod), "secondary",
|
||||
chip->chip_id == 1, &error_abort);
|
||||
object_property_set_link(OBJECT(&chip11->chiptod), "chip", OBJECT(chip),
|
||||
&error_abort);
|
||||
if (!qdev_realize(DEVICE(&chip11->chiptod), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_CHIPTOD_BASE,
|
||||
&chip11->chiptod.xscom_regs);
|
||||
|
||||
/* HOMER (must be created before OCC) */
|
||||
object_property_set_link(OBJECT(&chip11->homer), "chip", OBJECT(chip),
|
||||
&error_abort);
|
||||
if (!qdev_realize(DEVICE(&chip11->homer), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
/* Homer Xscom region */
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_PBA_BASE,
|
||||
&chip11->homer.pba_regs);
|
||||
/* Homer RAM region */
|
||||
memory_region_add_subregion(get_system_memory(), chip11->homer.base,
|
||||
&chip11->homer.mem);
|
||||
|
||||
/* Create the simplified OCC model */
|
||||
object_property_set_link(OBJECT(&chip11->occ), "homer",
|
||||
OBJECT(&chip11->homer), &error_abort);
|
||||
if (!qdev_realize(DEVICE(&chip11->occ), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_OCC_BASE,
|
||||
&chip11->occ.xscom_regs);
|
||||
qdev_connect_gpio_out(DEVICE(&chip11->occ), 0, qdev_get_gpio_in(
|
||||
DEVICE(&chip11->psi), PSIHB9_IRQ_OCC));
|
||||
|
||||
/* OCC SRAM model */
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
PNV11_OCC_SENSOR_BASE(chip),
|
||||
&chip11->occ.sram_regs);
|
||||
|
||||
/* SBE */
|
||||
if (!qdev_realize(DEVICE(&chip11->sbe), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_SBE_CTRL_BASE,
|
||||
&chip11->sbe.xscom_ctrl_regs);
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_SBE_MBOX_BASE,
|
||||
&chip11->sbe.xscom_mbox_regs);
|
||||
qdev_connect_gpio_out(DEVICE(&chip11->sbe), 0, qdev_get_gpio_in(
|
||||
DEVICE(&chip11->psi), PSIHB9_IRQ_PSU));
|
||||
|
||||
/* N1 chiplet */
|
||||
if (!qdev_realize(DEVICE(&chip11->n1_chiplet), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_N1_CHIPLET_CTRL_REGS_BASE,
|
||||
&chip11->n1_chiplet.nest_pervasive.xscom_ctrl_regs_mr);
|
||||
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_N1_PB_SCOM_EQ_BASE,
|
||||
&chip11->n1_chiplet.xscom_pb_eq_mr);
|
||||
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_N1_PB_SCOM_ES_BASE,
|
||||
&chip11->n1_chiplet.xscom_pb_es_mr);
|
||||
|
||||
/* PHBs */
|
||||
pnv_chip_power11_phb_realize(chip, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C
|
||||
*/
|
||||
for (i = 0; i < pcc->i2c_num_engines; i++) {
|
||||
Object *obj = OBJECT(&chip11->i2c[i]);
|
||||
|
||||
object_property_set_int(obj, "engine", i + 1, &error_fatal);
|
||||
object_property_set_int(obj, "num-busses",
|
||||
pcc->i2c_ports_per_engine[i],
|
||||
&error_fatal);
|
||||
object_property_set_link(obj, "chip", OBJECT(chip), &error_abort);
|
||||
if (!qdev_realize(DEVICE(obj), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_I2CM_BASE +
|
||||
(chip11->i2c[i].engine - 1) *
|
||||
PNV11_XSCOM_I2CM_SIZE,
|
||||
&chip11->i2c[i].xscom_regs);
|
||||
qdev_connect_gpio_out(DEVICE(&chip11->i2c[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&chip11->psi),
|
||||
PSIHB9_IRQ_SBE_I2C));
|
||||
}
|
||||
/* PIB SPI Controller */
|
||||
for (i = 0; i < PNV10_CHIP_MAX_PIB_SPIC; i++) {
|
||||
object_property_set_int(OBJECT(&chip11->pib_spic[i]), "spic_num",
|
||||
i, &error_fatal);
|
||||
/* pib_spic[2] connected to 25csm04 which implements 1 byte transfer */
|
||||
object_property_set_int(OBJECT(&chip11->pib_spic[i]), "transfer_len",
|
||||
(i == 2) ? 1 : 4, &error_fatal);
|
||||
object_property_set_int(OBJECT(&chip11->pib_spic[i]), "chip-id",
|
||||
chip->chip_id, &error_fatal);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(OBJECT
|
||||
(&chip11->pib_spic[i])), errp)) {
|
||||
return;
|
||||
}
|
||||
pnv_xscom_add_subregion(chip, PNV11_XSCOM_PIB_SPIC_BASE +
|
||||
i * PNV11_XSCOM_PIB_SPIC_SIZE,
|
||||
&chip11->pib_spic[i].xscom_spic_regs);
|
||||
}
|
||||
}
|
||||
|
||||
static void pnv_rainier_i2c_init(PnvMachineState *pnv)
|
||||
{
|
||||
int i;
|
||||
@@ -2401,6 +2820,7 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, const void *data)
|
||||
k->intc_reset = pnv_chip_power10_intc_reset;
|
||||
k->intc_destroy = pnv_chip_power10_intc_destroy;
|
||||
k->intc_print_info = pnv_chip_power10_intc_print_info;
|
||||
k->intc_get = pnv_chip_power10_intc_get;
|
||||
k->isa_create = pnv_chip_power10_isa_create;
|
||||
k->dt_populate = pnv_chip_power10_dt_populate;
|
||||
k->pic_print_info = pnv_chip_power10_pic_print_info;
|
||||
@@ -2415,6 +2835,40 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, const void *data)
|
||||
&k->parent_realize);
|
||||
}
|
||||
|
||||
static uint32_t pnv_chip_power11_xscom_pcba(PnvChip *chip, uint64_t addr)
|
||||
{
|
||||
addr &= (PNV11_XSCOM_SIZE - 1);
|
||||
return addr >> 3;
|
||||
}
|
||||
|
||||
static void pnv_chip_power11_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PnvChipClass *k = PNV_CHIP_CLASS(klass);
|
||||
static const int i2c_ports_per_engine[PNV10_CHIP_MAX_I2C] = {14, 14, 2, 16};
|
||||
|
||||
k->chip_cfam_id = 0x220da04980000000ull; /* P11 DD2.0 (with NX) */
|
||||
k->cores_mask = POWER11_CORE_MASK;
|
||||
k->get_pir_tir = pnv_get_pir_tir_p10;
|
||||
k->intc_create = pnv_chip_power11_intc_create;
|
||||
k->intc_reset = pnv_chip_power11_intc_reset;
|
||||
k->intc_destroy = pnv_chip_power11_intc_destroy;
|
||||
k->intc_print_info = pnv_chip_power11_intc_print_info;
|
||||
k->intc_get = pnv_chip_power11_intc_get;
|
||||
k->isa_create = pnv_chip_power11_isa_create;
|
||||
k->dt_populate = pnv_chip_power11_dt_populate;
|
||||
k->pic_print_info = pnv_chip_power11_pic_print_info;
|
||||
k->xscom_core_base = pnv_chip_power11_xscom_core_base;
|
||||
k->xscom_pcba = pnv_chip_power11_xscom_pcba;
|
||||
dc->desc = "PowerNV Chip Power11";
|
||||
k->num_pecs = PNV10_CHIP_MAX_PEC;
|
||||
k->i2c_num_engines = PNV10_CHIP_MAX_I2C;
|
||||
k->i2c_ports_per_engine = i2c_ports_per_engine;
|
||||
|
||||
device_class_set_parent_realize(dc, pnv_chip_power11_realize,
|
||||
&k->parent_realize);
|
||||
}
|
||||
|
||||
static void pnv_chip_core_sanitize(PnvMachineState *pnv, PnvChip *chip,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -2754,6 +3208,45 @@ static int pnv10_xive_broadcast(XiveFabric *xfb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool pnv11_xive_match_nvt(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv,
|
||||
XiveTCTXMatch *match)
|
||||
{
|
||||
PnvMachineState *pnv = PNV_MACHINE(xfb);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pnv->num_chips; i++) {
|
||||
Pnv11Chip *chip11 = PNV11_CHIP(pnv->chips[i]);
|
||||
XivePresenter *xptr = XIVE_PRESENTER(&chip11->xive);
|
||||
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
|
||||
|
||||
xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd,
|
||||
cam_ignore, priority, logic_serv, match);
|
||||
}
|
||||
|
||||
return !!match->count;
|
||||
}
|
||||
|
||||
static int pnv11_xive_broadcast(XiveFabric *xfb,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore,
|
||||
uint8_t priority)
|
||||
{
|
||||
PnvMachineState *pnv = PNV_MACHINE(xfb);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pnv->num_chips; i++) {
|
||||
Pnv11Chip *chip11 = PNV11_CHIP(pnv->chips[i]);
|
||||
XivePresenter *xptr = XIVE_PRESENTER(&chip11->xive);
|
||||
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
|
||||
|
||||
xpc->broadcast(xptr, nvt_blk, nvt_idx, crowd, cam_ignore, priority);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool pnv_machine_get_big_core(Object *obj, Error **errp)
|
||||
{
|
||||
PnvMachineState *pnv = PNV_MACHINE(obj);
|
||||
@@ -2928,6 +3421,46 @@ static void pnv_machine_p10_rainier_class_init(ObjectClass *oc,
|
||||
pmc->i2c_init = pnv_rainier_i2c_init;
|
||||
}
|
||||
|
||||
static void pnv_machine_power11_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
|
||||
XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc);
|
||||
static const char compat[] = "qemu,powernv11\0ibm,powernv";
|
||||
|
||||
static GlobalProperty phb_compat[] = {
|
||||
{ TYPE_PNV_PHB, "version", "5" },
|
||||
{ TYPE_PNV_PHB_ROOT_PORT, "version", "5" },
|
||||
};
|
||||
|
||||
compat_props_add(mc->compat_props, phb_compat, G_N_ELEMENTS(phb_compat));
|
||||
|
||||
pmc->compat = compat;
|
||||
pmc->compat_size = sizeof(compat);
|
||||
pmc->max_smt_threads = 4;
|
||||
pmc->has_lpar_per_thread = true;
|
||||
pmc->quirk_tb_big_core = true;
|
||||
pmc->dt_power_mgt = pnv_dt_power_mgt;
|
||||
|
||||
xfc->match_nvt = pnv11_xive_match_nvt;
|
||||
xfc->broadcast = pnv11_xive_broadcast;
|
||||
|
||||
mc->desc = "IBM PowerNV (Non-Virtualized) Power11";
|
||||
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power11_v2.0");
|
||||
|
||||
object_class_property_add_bool(oc, "big-core",
|
||||
pnv_machine_get_big_core,
|
||||
pnv_machine_set_big_core);
|
||||
object_class_property_set_description(oc, "big-core",
|
||||
"Use big-core (aka fused-core) mode");
|
||||
|
||||
object_class_property_add_bool(oc, "lpar-per-core",
|
||||
pnv_machine_get_lpar_per_core,
|
||||
pnv_machine_set_lpar_per_core);
|
||||
object_class_property_set_description(oc, "lpar-per-core",
|
||||
"Use 1 LPAR per core mode");
|
||||
}
|
||||
|
||||
static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
|
||||
{
|
||||
CPUPPCState *env = cpu_env(cs);
|
||||
@@ -3033,7 +3566,23 @@ static void pnv_machine_class_init(ObjectClass *oc, const void *data)
|
||||
.parent = TYPE_PNV10_CHIP, \
|
||||
}
|
||||
|
||||
#define DEFINE_PNV11_CHIP_TYPE(type, class_initfn) \
|
||||
{ \
|
||||
.name = type, \
|
||||
.class_init = class_initfn, \
|
||||
.parent = TYPE_PNV11_CHIP, \
|
||||
}
|
||||
|
||||
static const TypeInfo types[] = {
|
||||
{
|
||||
.name = MACHINE_TYPE_NAME("powernv11"),
|
||||
.parent = TYPE_PNV_MACHINE,
|
||||
.class_init = pnv_machine_power11_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_XIVE_FABRIC },
|
||||
{ },
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = MACHINE_TYPE_NAME("powernv10-rainier"),
|
||||
.parent = MACHINE_TYPE_NAME("powernv10"),
|
||||
@@ -3088,6 +3637,17 @@ static const TypeInfo types[] = {
|
||||
.abstract = true,
|
||||
},
|
||||
|
||||
/*
|
||||
* P11 chip and variants
|
||||
*/
|
||||
{
|
||||
.name = TYPE_PNV11_CHIP,
|
||||
.parent = TYPE_PNV_CHIP,
|
||||
.instance_init = pnv_chip_power11_instance_init,
|
||||
.instance_size = sizeof(Pnv11Chip),
|
||||
},
|
||||
DEFINE_PNV11_CHIP_TYPE(TYPE_PNV_CHIP_POWER11, pnv_chip_power11_class_init),
|
||||
|
||||
/*
|
||||
* P10 chip and variants
|
||||
*/
|
||||
|
||||
@@ -210,6 +210,22 @@ static void chiptod_power10_broadcast_ttype(PnvChipTOD *sender,
|
||||
}
|
||||
}
|
||||
|
||||
static void chiptod_power11_broadcast_ttype(PnvChipTOD *sender,
|
||||
uint32_t trigger)
|
||||
{
|
||||
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pnv->num_chips; i++) {
|
||||
Pnv11Chip *chip11 = PNV11_CHIP(pnv->chips[i]);
|
||||
PnvChipTOD *chiptod = &chip11->chiptod;
|
||||
|
||||
if (chiptod != sender) {
|
||||
chiptod_receive_ttype(chiptod, trigger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PnvCore *pnv_chip_get_core_by_xscom_base(PnvChip *chip,
|
||||
uint32_t xscom_base)
|
||||
{
|
||||
@@ -283,6 +299,12 @@ static PnvCore *chiptod_power10_tx_ttype_target(PnvChipTOD *chiptod,
|
||||
}
|
||||
}
|
||||
|
||||
static PnvCore *chiptod_power11_tx_ttype_target(PnvChipTOD *chiptod,
|
||||
uint64_t val)
|
||||
{
|
||||
return chiptod_power10_tx_ttype_target(chiptod, val);
|
||||
}
|
||||
|
||||
static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
@@ -520,6 +542,42 @@ static const TypeInfo pnv_chiptod_power10_type_info = {
|
||||
}
|
||||
};
|
||||
|
||||
static int pnv_chiptod_power11_dt_xscom(PnvXScomInterface *dev, void *fdt,
|
||||
int xscom_offset)
|
||||
{
|
||||
const char compat[] = "ibm,power-chiptod\0ibm,power11-chiptod";
|
||||
|
||||
return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat));
|
||||
}
|
||||
|
||||
static void pnv_chiptod_power11_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
|
||||
|
||||
dc->desc = "PowerNV ChipTOD Controller (Power11)";
|
||||
device_class_set_props(dc, pnv_chiptod_properties);
|
||||
|
||||
xdc->dt_xscom = pnv_chiptod_power11_dt_xscom;
|
||||
|
||||
pctc->broadcast_ttype = chiptod_power11_broadcast_ttype;
|
||||
pctc->tx_ttype_target = chiptod_power11_tx_ttype_target;
|
||||
|
||||
pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE;
|
||||
}
|
||||
|
||||
static const TypeInfo pnv_chiptod_power11_type_info = {
|
||||
.name = TYPE_PNV11_CHIPTOD,
|
||||
.parent = TYPE_PNV_CHIPTOD,
|
||||
.instance_size = sizeof(PnvChipTOD),
|
||||
.class_init = pnv_chiptod_power11_class_init,
|
||||
.interfaces = (const InterfaceInfo[]) {
|
||||
{ TYPE_PNV_XSCOM_INTERFACE },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
static void pnv_chiptod_reset(void *dev)
|
||||
{
|
||||
PnvChipTOD *chiptod = PNV_CHIPTOD(dev);
|
||||
@@ -579,6 +637,7 @@ static void pnv_chiptod_register_types(void)
|
||||
type_register_static(&pnv_chiptod_type_info);
|
||||
type_register_static(&pnv_chiptod_power9_type_info);
|
||||
type_register_static(&pnv_chiptod_power10_type_info);
|
||||
type_register_static(&pnv_chiptod_power11_type_info);
|
||||
}
|
||||
|
||||
type_init(pnv_chiptod_register_types);
|
||||
|
||||
@@ -473,6 +473,11 @@ static void pnv_core_power10_class_init(ObjectClass *oc, const void *data)
|
||||
pcc->xscom_size = PNV10_XSCOM_EC_SIZE;
|
||||
}
|
||||
|
||||
static void pnv_core_power11_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
pnv_core_power10_class_init(oc, data);
|
||||
}
|
||||
|
||||
static void pnv_core_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
@@ -504,6 +509,7 @@ static const TypeInfo pnv_core_infos[] = {
|
||||
DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
|
||||
DEFINE_PNV_CORE_TYPE(power9, "power9_v2.2"),
|
||||
DEFINE_PNV_CORE_TYPE(power10, "power10_v2.0"),
|
||||
DEFINE_PNV_CORE_TYPE(power11, "power11_v2.0"),
|
||||
};
|
||||
|
||||
DEFINE_TYPES(pnv_core_infos)
|
||||
@@ -725,6 +731,12 @@ static void pnv_quad_power10_class_init(ObjectClass *oc, const void *data)
|
||||
pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE;
|
||||
}
|
||||
|
||||
static void pnv_quad_power11_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
/* Power11 quad is similar to Power10 quad */
|
||||
pnv_quad_power10_class_init(oc, data);
|
||||
}
|
||||
|
||||
static void pnv_quad_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
@@ -752,6 +764,11 @@ static const TypeInfo pnv_quad_infos[] = {
|
||||
.name = PNV_QUAD_TYPE_NAME("power10"),
|
||||
.class_init = pnv_quad_power10_class_init,
|
||||
},
|
||||
{
|
||||
.parent = TYPE_PNV_QUAD,
|
||||
.name = PNV_QUAD_TYPE_NAME("power11"),
|
||||
.class_init = pnv_quad_power11_class_init,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(pnv_quad_infos);
|
||||
|
||||
+6
-1
@@ -352,7 +352,12 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
|
||||
booke_timer = g_new0(booke_timer_t, 1);
|
||||
|
||||
cpu->env.tb_env = tb_env;
|
||||
tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
|
||||
if (flags & PPC_TIMER_PPE) {
|
||||
/* PPE's use a modified version of the booke behavior */
|
||||
tb_env->flags = flags | PPC_DECR_UNDERFLOW_TRIGGERED;
|
||||
} else {
|
||||
tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
|
||||
}
|
||||
|
||||
tb_env->tb_freq = freq;
|
||||
tb_env->decr_freq = freq;
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Test Machine for the IBM PPE42 processor
|
||||
*
|
||||
* Copyright (c) 2025, IBM Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "system/address-spaces.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/ppc/ppc.h"
|
||||
#include "system/system.h"
|
||||
#include "system/reset.h"
|
||||
#include "system/kvm.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#define TYPE_PPE42_MACHINE MACHINE_TYPE_NAME("ppe42_machine")
|
||||
typedef MachineClass Ppe42MachineClass;
|
||||
typedef struct Ppe42MachineState Ppe42MachineState;
|
||||
DECLARE_OBJ_CHECKERS(Ppe42MachineState, Ppe42MachineClass,
|
||||
PPE42_MACHINE, TYPE_PPE42_MACHINE)
|
||||
|
||||
struct Ppe42MachineState {
|
||||
MachineState parent_obj;
|
||||
|
||||
PowerPCCPU cpu;
|
||||
};
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
|
||||
cpu_reset(CPU(cpu));
|
||||
}
|
||||
|
||||
static void ppe42_machine_init(MachineState *machine)
|
||||
{
|
||||
Ppe42MachineState *pms = PPE42_MACHINE(machine);
|
||||
PowerPCCPU *cpu = &pms->cpu;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
error_report("machine %s does not support the KVM accelerator",
|
||||
MACHINE_GET_CLASS(machine)->name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (machine->ram_size > 512 * KiB) {
|
||||
error_report("RAM size more than 512 KiB is not supported");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* init CPU */
|
||||
object_initialize_child(OBJECT(pms), "cpu", cpu, machine->cpu_type);
|
||||
if (!qdev_realize(DEVICE(cpu), NULL, &error_fatal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_register_reset(main_cpu_reset, cpu);
|
||||
|
||||
/* This sets the decrementer timebase */
|
||||
ppc_booke_timers_init(cpu, 37500000, PPC_TIMER_PPE);
|
||||
|
||||
/* RAM */
|
||||
memory_region_add_subregion(get_system_memory(), 0xfff80000, machine->ram);
|
||||
}
|
||||
|
||||
|
||||
static void ppe42_machine_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
static const char * const valid_cpu_types[] = {
|
||||
POWERPC_CPU_TYPE_NAME("PPE42"),
|
||||
POWERPC_CPU_TYPE_NAME("PPE42X"),
|
||||
POWERPC_CPU_TYPE_NAME("PPE42XM"),
|
||||
NULL,
|
||||
};
|
||||
|
||||
mc->desc = "PPE42 Test Machine";
|
||||
mc->init = ppe42_machine_init;
|
||||
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("PPE42XM");
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
mc->default_ram_id = "ram";
|
||||
mc->default_ram_size = 512 * KiB;
|
||||
}
|
||||
|
||||
static const TypeInfo ppe42_machine_info = {
|
||||
.name = TYPE_PPE42_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(Ppe42MachineState),
|
||||
.class_init = ppe42_machine_class_init,
|
||||
.class_size = sizeof(Ppe42MachineClass),
|
||||
};
|
||||
|
||||
static void ppe42_machine_register_types(void)
|
||||
{
|
||||
type_register_static(&ppe42_machine_info);
|
||||
}
|
||||
|
||||
type_init(ppe42_machine_register_types);
|
||||
+7
-4
@@ -907,6 +907,7 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
|
||||
int rtas;
|
||||
GString *hypertas = g_string_sized_new(256);
|
||||
GString *qemu_hypertas = g_string_sized_new(256);
|
||||
uint64_t max_device_addr = 0;
|
||||
uint32_t lrdr_capacity[] = {
|
||||
0,
|
||||
0,
|
||||
@@ -917,13 +918,15 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
|
||||
|
||||
/* Do we have device memory? */
|
||||
if (MACHINE(spapr)->device_memory) {
|
||||
uint64_t max_device_addr = MACHINE(spapr)->device_memory->base +
|
||||
max_device_addr = MACHINE(spapr)->device_memory->base +
|
||||
memory_region_size(&MACHINE(spapr)->device_memory->mr);
|
||||
|
||||
lrdr_capacity[0] = cpu_to_be32(max_device_addr >> 32);
|
||||
lrdr_capacity[1] = cpu_to_be32(max_device_addr & 0xffffffff);
|
||||
} else if (ms->ram_size == ms->maxram_size) {
|
||||
max_device_addr = ms->ram_size;
|
||||
}
|
||||
|
||||
lrdr_capacity[0] = cpu_to_be32(max_device_addr >> 32);
|
||||
lrdr_capacity[1] = cpu_to_be32(max_device_addr & 0xffffffff);
|
||||
|
||||
_FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
|
||||
|
||||
/* hypertas */
|
||||
|
||||
@@ -33,6 +33,7 @@ typedef struct PnvChip PnvChip;
|
||||
typedef struct Pnv8Chip Pnv8Chip;
|
||||
typedef struct Pnv9Chip Pnv9Chip;
|
||||
typedef struct Pnv10Chip Pnv10Chip;
|
||||
typedef struct Pnv10Chip Pnv11Chip;
|
||||
|
||||
#define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP
|
||||
#define PNV_CHIP_TYPE_NAME(cpu_model) cpu_model PNV_CHIP_TYPE_SUFFIX
|
||||
@@ -57,6 +58,10 @@ DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER9,
|
||||
DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10,
|
||||
TYPE_PNV_CHIP_POWER10)
|
||||
|
||||
#define TYPE_PNV_CHIP_POWER11 PNV_CHIP_TYPE_NAME("power11_v2.0")
|
||||
DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER11,
|
||||
TYPE_PNV_CHIP_POWER11)
|
||||
|
||||
PnvCore *pnv_chip_find_core(PnvChip *chip, uint32_t core_id);
|
||||
PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir);
|
||||
|
||||
@@ -252,4 +257,37 @@ void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor);
|
||||
#define PNV10_HOMER_BASE(chip) \
|
||||
(0x300ffd800000ll + ((uint64_t)(chip)->chip_id) * PNV_HOMER_SIZE)
|
||||
|
||||
/* Power11 */
|
||||
#define PNV11_XSCOM_SIZE PNV10_XSCOM_SIZE
|
||||
#define PNV11_XSCOM_BASE(chip) PNV10_XSCOM_BASE(chip)
|
||||
|
||||
#define PNV11_LPCM_SIZE PNV10_LPCM_SIZE
|
||||
#define PNV11_LPCM_BASE(chip) PNV10_LPCM_BASE(chip)
|
||||
|
||||
#define PNV11_PSIHB_ESB_SIZE PNV10_PSIHB_ESB_SIZE
|
||||
#define PNV11_PSIHB_ESB_BASE(chip) PNV10_PSIHB_ESB_BASE(chip)
|
||||
|
||||
#define PNV11_PSIHB_SIZE PNV10_PSIHB_SIZE
|
||||
#define PNV11_PSIHB_BASE(chip) PNV10_PSIHB_BASE(chip)
|
||||
|
||||
#define PNV11_XIVE2_IC_SIZE PNV10_XIVE2_IC_SIZE
|
||||
#define PNV11_XIVE2_IC_BASE(chip) PNV10_XIVE2_IC_BASE(chip)
|
||||
|
||||
#define PNV11_XIVE2_TM_SIZE PNV10_XIVE2_TM_SIZE
|
||||
#define PNV11_XIVE2_TM_BASE(chip) PNV10_XIVE2_TM_BASE(chip)
|
||||
|
||||
#define PNV11_XIVE2_NVC_SIZE PNV10_XIVE2_NVC_SIZE
|
||||
#define PNV11_XIVE2_NVC_BASE(chip) PNV10_XIVE2_NVC_BASE(chip)
|
||||
|
||||
#define PNV11_XIVE2_NVPG_SIZE PNV10_XIVE2_NVPG_SIZE
|
||||
#define PNV11_XIVE2_NVPG_BASE(chip) PNV10_XIVE2_NVPG_BASE(chip)
|
||||
|
||||
#define PNV11_XIVE2_ESB_SIZE PNV10_XIVE2_ESB_SIZE
|
||||
#define PNV11_XIVE2_ESB_BASE(chip) PNV10_XIVE2_ESB_BASE(chip)
|
||||
|
||||
#define PNV11_XIVE2_END_SIZE PNV10_XIVE2_END_SIZE
|
||||
#define PNV11_XIVE2_END_BASE(chip) PNV10_XIVE2_END_BASE(chip)
|
||||
|
||||
#define PNV11_OCC_SENSOR_BASE(chip) PNV10_OCC_SENSOR_BASE(chip)
|
||||
|
||||
#endif /* PPC_PNV_H */
|
||||
|
||||
@@ -141,6 +141,13 @@ struct Pnv10Chip {
|
||||
#define PNV10_PIR2CHIP(pir) (((pir) >> 8) & 0x7f)
|
||||
#define PNV10_PIR2THREAD(pir) (((pir) & 0x7f))
|
||||
|
||||
#define TYPE_PNV11_CHIP "pnv11-chip"
|
||||
DECLARE_INSTANCE_CHECKER(Pnv11Chip, PNV11_CHIP,
|
||||
TYPE_PNV11_CHIP)
|
||||
|
||||
/* Power11 core is same as Power10 */
|
||||
typedef struct Pnv10Chip Pnv11Chip;
|
||||
|
||||
struct PnvChipClass {
|
||||
/*< private >*/
|
||||
SysBusDeviceClass parent_class;
|
||||
@@ -163,6 +170,7 @@ struct PnvChipClass {
|
||||
void (*intc_reset)(PnvChip *chip, PowerPCCPU *cpu);
|
||||
void (*intc_destroy)(PnvChip *chip, PowerPCCPU *cpu);
|
||||
void (*intc_print_info)(PnvChip *chip, PowerPCCPU *cpu, GString *buf);
|
||||
void* (*intc_get)(PnvChip *chip);
|
||||
ISABus *(*isa_create)(PnvChip *chip, Error **errp);
|
||||
void (*dt_populate)(PnvChip *chip, void *fdt);
|
||||
void (*pic_print_info)(PnvChip *chip, GString *buf);
|
||||
|
||||
@@ -17,6 +17,8 @@ OBJECT_DECLARE_TYPE(PnvChipTOD, PnvChipTODClass, PNV_CHIPTOD)
|
||||
DECLARE_INSTANCE_CHECKER(PnvChipTOD, PNV9_CHIPTOD, TYPE_PNV9_CHIPTOD)
|
||||
#define TYPE_PNV10_CHIPTOD TYPE_PNV_CHIPTOD "-POWER10"
|
||||
DECLARE_INSTANCE_CHECKER(PnvChipTOD, PNV10_CHIPTOD, TYPE_PNV10_CHIPTOD)
|
||||
#define TYPE_PNV11_CHIPTOD TYPE_PNV_CHIPTOD "-POWER11"
|
||||
DECLARE_INSTANCE_CHECKER(PnvChipTOD, PNV11_CHIPTOD, TYPE_PNV11_CHIPTOD)
|
||||
|
||||
enum tod_state {
|
||||
tod_error = 0,
|
||||
|
||||
@@ -207,6 +207,55 @@ struct PnvXScomInterfaceClass {
|
||||
#define PNV10_XSCOM_PIB_SPIC_BASE 0xc0000
|
||||
#define PNV10_XSCOM_PIB_SPIC_SIZE 0x20
|
||||
|
||||
/*
|
||||
* Power11 core is same as Power10
|
||||
*/
|
||||
#define PNV11_XSCOM_EC_BASE(core) PNV10_XSCOM_EC_BASE(core)
|
||||
|
||||
#define PNV11_XSCOM_ADU_BASE PNV10_XSCOM_ADU_BASE
|
||||
#define PNV11_XSCOM_ADU_SIZE PNV10_XSCOM_ADU_SIZE
|
||||
|
||||
#define PNV11_XSCOM_QME_BASE(core) PNV10_XSCOM_QME_BASE(core)
|
||||
|
||||
#define PNV11_XSCOM_EQ_BASE(core) PNV10_XSCOM_EQ_BASE(core)
|
||||
|
||||
#define PNV11_XSCOM_PSIHB_BASE PNV10_XSCOM_PSIHB_BASE
|
||||
#define PNV11_XSCOM_PSIHB_SIZE PNV10_XSCOM_PSIHB_SIZE
|
||||
|
||||
#define PNV11_XSCOM_I2CM_BASE PNV10_XSCOM_I2CM_BASE
|
||||
#define PNV11_XSCOM_I2CM_SIZE PNV10_XSCOM_I2CM_SIZE
|
||||
|
||||
#define PNV11_XSCOM_CHIPTOD_BASE PNV10_XSCOM_CHIPTOD_BASE
|
||||
#define PNV11_XSCOM_CHIPTOD_SIZE PNV10_XSCOM_CHIPTOD_SIZE
|
||||
|
||||
#define PNV11_XSCOM_OCC_BASE PNV10_XSCOM_OCC_BASE
|
||||
#define PNV11_XSCOM_OCC_SIZE PNV10_XSCOM_OCC_SIZE
|
||||
|
||||
#define PNV11_XSCOM_SBE_CTRL_BASE PNV10_XSCOM_SBE_CTRL_BASE
|
||||
#define PNV11_XSCOM_SBE_CTRL_SIZE PNV10_XSCOM_SBE_CTRL_SIZE
|
||||
|
||||
#define PNV11_XSCOM_SBE_MBOX_BASE PNV10_XSCOM_SBE_MBOX_BASE
|
||||
#define PNV11_XSCOM_SBE_MBOX_SIZE PNV10_XSCOM_SBE_MBOX_SIZE
|
||||
|
||||
#define PNV11_XSCOM_PBA_BASE PNV10_XSCOM_PBA_BASE
|
||||
#define PNV11_XSCOM_PBA_SIZE PNV10_XSCOM_PBA_SIZE
|
||||
|
||||
#define PNV11_XSCOM_XIVE2_BASE PNV10_XSCOM_XIVE2_BASE
|
||||
#define PNV11_XSCOM_XIVE2_SIZE PNV10_XSCOM_XIVE2_SIZE
|
||||
|
||||
#define PNV11_XSCOM_N1_CHIPLET_CTRL_REGS_BASE \
|
||||
PNV10_XSCOM_N1_CHIPLET_CTRL_REGS_BASE
|
||||
#define PNV11_XSCOM_CHIPLET_CTRL_REGS_SIZE PNV10_XSCOM_CHIPLET_CTRL_REGS_SIZE
|
||||
|
||||
#define PNV11_XSCOM_N1_PB_SCOM_EQ_BASE PNV10_XSCOM_N1_PB_SCOM_EQ_BASE
|
||||
#define PNV11_XSCOM_N1_PB_SCOM_EQ_SIZE PNV10_XSCOM_N1_PB_SCOM_EQ_SIZE
|
||||
|
||||
#define PNV11_XSCOM_N1_PB_SCOM_ES_BASE PNV10_XSCOM_N1_PB_SCOM_ES_BASE
|
||||
#define PNV11_XSCOM_N1_PB_SCOM_ES_SIZE PNV10_XSCOM_N1_PB_SCOM_ES_SIZE
|
||||
|
||||
#define PNV11_XSCOM_PIB_SPIC_BASE PNV10_XSCOM_PIB_SPIC_BASE
|
||||
#define PNV11_XSCOM_PIB_SPIC_SIZE PNV10_XSCOM_PIB_SPIC_SIZE
|
||||
|
||||
void pnv_xscom_init(PnvChip *chip, uint64_t size, hwaddr addr);
|
||||
int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset,
|
||||
uint64_t xscom_base, uint64_t xscom_size,
|
||||
|
||||
@@ -52,6 +52,7 @@ struct ppc_tb_t {
|
||||
#define PPC_DECR_UNDERFLOW_LEVEL (1 << 4) /* Decr interrupt active when
|
||||
* the most significant bit is 1.
|
||||
*/
|
||||
#define PPC_TIMER_PPE (1 << 5) /* Enable PPE support */
|
||||
|
||||
uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
|
||||
void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq);
|
||||
|
||||
+22
-5
@@ -32,17 +32,20 @@
|
||||
/* PowerPC CPU definitions */
|
||||
#define POWERPC_DEF_PREFIX(pvr, svr, type) \
|
||||
glue(glue(glue(glue(pvr, _), svr), _), type)
|
||||
#define POWERPC_DEF_SVR(_name, _desc, _pvr, _svr, _type) \
|
||||
#define POWERPC_DEF_SVR_DEPR(_name, _desc, _pvr, _svr, _type, _deprecation_note) \
|
||||
static void \
|
||||
glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init) \
|
||||
(ObjectClass *oc, const void *data) \
|
||||
{ \
|
||||
DeviceClass *dc = DEVICE_CLASS(oc); \
|
||||
CPUClass *cc = CPU_CLASS(oc); \
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); \
|
||||
\
|
||||
pcc->pvr = _pvr; \
|
||||
pcc->svr = _svr; \
|
||||
dc->desc = _desc; \
|
||||
\
|
||||
cc->deprecation_note = _deprecation_note; \
|
||||
} \
|
||||
\
|
||||
static const TypeInfo \
|
||||
@@ -63,6 +66,13 @@
|
||||
type_init( \
|
||||
glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_register_types))
|
||||
|
||||
#define POWERPC_DEF_SVR(_name, _desc, _pvr, _svr, _type) \
|
||||
POWERPC_DEF_SVR_DEPR(_name, _desc, _pvr, _svr, _type, NULL)
|
||||
|
||||
#define POWERPC_DEPRECATED_CPU(_name, _pvr, _type, _desc, _deprecation_note)\
|
||||
POWERPC_DEF_SVR_DEPR(_name, _desc, _pvr, POWERPC_SVR_NONE, _type, \
|
||||
_deprecation_note)
|
||||
|
||||
#define POWERPC_DEF(_name, _pvr, _type, _desc) \
|
||||
POWERPC_DEF_SVR(_name, _desc, _pvr, POWERPC_SVR_NONE, _type)
|
||||
|
||||
@@ -116,6 +126,13 @@
|
||||
NULL)
|
||||
POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405,
|
||||
NULL)
|
||||
/* PPE42 Embedded Controllers */
|
||||
POWERPC_DEF("PPE42", CPU_POWERPC_PPE42, ppe42,
|
||||
"Generic PPE 42")
|
||||
POWERPC_DEF("PPE42X", CPU_POWERPC_PPE42X, ppe42x,
|
||||
"Generic PPE 42X")
|
||||
POWERPC_DEF("PPE42XM", CPU_POWERPC_PPE42XM, ppe42xm,
|
||||
"Generic PPE 42XM")
|
||||
/* PowerPC 440 family */
|
||||
#if defined(TODO_USER_ONLY)
|
||||
POWERPC_DEF("440", CPU_POWERPC_440, 440GP,
|
||||
@@ -722,12 +739,12 @@
|
||||
"POWER7 v2.3")
|
||||
POWERPC_DEF("power7p_v2.1", CPU_POWERPC_POWER7P_v21, POWER7,
|
||||
"POWER7+ v2.1")
|
||||
POWERPC_DEF("power8e_v2.1", CPU_POWERPC_POWER8E_v21, POWER8,
|
||||
"POWER8E v2.1")
|
||||
POWERPC_DEPRECATED_CPU("power8e_v2.1", CPU_POWERPC_POWER8E_v21, POWER8,
|
||||
"POWER8E v2.1", "CPU is unmaintained.")
|
||||
POWERPC_DEF("power8_v2.0", CPU_POWERPC_POWER8_v20, POWER8,
|
||||
"POWER8 v2.0")
|
||||
POWERPC_DEF("power8nvl_v1.0", CPU_POWERPC_POWER8NVL_v10, POWER8,
|
||||
"POWER8NVL v1.0")
|
||||
POWERPC_DEPRECATED_CPU("power8nvl_v1.0", CPU_POWERPC_POWER8NVL_v10, POWER8,
|
||||
"POWER8NVL v1.0", "CPU is unmaintained.")
|
||||
POWERPC_DEF("power9_v2.0", CPU_POWERPC_POWER9_DD20, POWER9,
|
||||
"POWER9 v2.0")
|
||||
POWERPC_DEF("power9_v2.2", CPU_POWERPC_POWER9_DD22, POWER9,
|
||||
|
||||
@@ -69,6 +69,10 @@ enum {
|
||||
/* Xilinx cores */
|
||||
CPU_POWERPC_X2VP4 = 0x20010820,
|
||||
CPU_POWERPC_X2VP20 = 0x20010860,
|
||||
/* IBM PPE42 Family */
|
||||
CPU_POWERPC_PPE42 = 0x42000000,
|
||||
CPU_POWERPC_PPE42X = 0x42100000,
|
||||
CPU_POWERPC_PPE42XM = 0x42200000,
|
||||
/* PowerPC 440 family */
|
||||
/* Generic PowerPC 440 */
|
||||
#define CPU_POWERPC_440 CPU_POWERPC_440GXf
|
||||
|
||||
+75
-1
@@ -220,6 +220,8 @@ typedef enum powerpc_excp_t {
|
||||
POWERPC_EXCP_POWER10,
|
||||
/* POWER11 exception model */
|
||||
POWERPC_EXCP_POWER11,
|
||||
/* PPE42 exception model */
|
||||
POWERPC_EXCP_PPE42,
|
||||
} powerpc_excp_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -282,6 +284,8 @@ typedef enum powerpc_input_t {
|
||||
PPC_FLAGS_INPUT_POWER9,
|
||||
/* Freescale RCPU bus */
|
||||
PPC_FLAGS_INPUT_RCPU,
|
||||
/* PPE42 bus */
|
||||
PPC_FLAGS_INPUT_PPE42,
|
||||
} powerpc_input_t;
|
||||
|
||||
#define PPC_INPUT(env) ((env)->bus_model)
|
||||
@@ -433,39 +437,64 @@ typedef enum {
|
||||
#define MSR_TM PPC_BIT_NR(31) /* Transactional Memory Available (Book3s) */
|
||||
#define MSR_CM PPC_BIT_NR(32) /* Computation mode for BookE hflags */
|
||||
#define MSR_ICM PPC_BIT_NR(33) /* Interrupt computation mode for BookE */
|
||||
#define MSR_SEM0 PPC_BIT_NR(33) /* SIB Error Mask Bit 0 (PPE42) */
|
||||
#define MSR_SEM1 PPC_BIT_NR(34) /* SIB Error Mask Bit 1 (PPE42) */
|
||||
#define MSR_SEM2 PPC_BIT_NR(35) /* SIB Error Mask Bit 2 (PPE42) */
|
||||
#define MSR_GS PPC_BIT_NR(35) /* guest state for BookE */
|
||||
#define MSR_SEM3 PPC_BIT_NR(36) /* SIB Error Mask Bit 3 (PPE42) */
|
||||
#define MSR_SEM4 PPC_BIT_NR(37) /* SIB Error Mask Bit 4 (PPE42) */
|
||||
#define MSR_UCLE PPC_BIT_NR(37) /* User-mode cache lock enable for BookE */
|
||||
#define MSR_VR PPC_BIT_NR(38) /* altivec available x hflags */
|
||||
#define MSR_SPE PPC_BIT_NR(38) /* SPE enable for BookE x hflags */
|
||||
#define MSR_SEM5 PPC_BIT_NR(38) /* SIB Error Mask Bit 5 (PPE42) */
|
||||
#define MSR_SEM6 PPC_BIT_NR(39) /* SIB Error Mask Bit 6 (PPE42) */
|
||||
#define MSR_VSX PPC_BIT_NR(40) /* Vector Scalar Extension (>= 2.06)x hflags */
|
||||
#define MSR_IS0 PPC_BIT_NR(40) /* Instance Specific Bit 0 (PPE42) */
|
||||
#define MSR_S PPC_BIT_NR(41) /* Secure state */
|
||||
#define MSR_SIBRC0 PPC_BIT_NR(41) /* Last SIB return code Bit 0 (PPE42) */
|
||||
#define MSR_SIBRC1 PPC_BIT_NR(42) /* Last SIB return code Bit 1 (PPE42) */
|
||||
#define MSR_SIBRC2 PPC_BIT_NR(43) /* Last SIB return code Bit 2 (PPE42) */
|
||||
#define MSR_LP PPC_BIT_NR(44) /* Low Priority (PPE42) */
|
||||
#define MSR_KEY PPC_BIT_NR(44) /* key bit on 603e */
|
||||
#define MSR_POW PPC_BIT_NR(45) /* Power management */
|
||||
#define MSR_WE PPC_BIT_NR(45) /* Wait State Enable on 405 */
|
||||
#define MSR_IS1 PPC_BIT_NR(46) /* Instance Specific Bit 1 (PPE42) */
|
||||
#define MSR_TGPR PPC_BIT_NR(46) /* TGPR usage on 602/603 x */
|
||||
#define MSR_CE PPC_BIT_NR(46) /* Critical int. enable on embedded PPC x */
|
||||
#define MSR_ILE PPC_BIT_NR(47) /* Interrupt little-endian mode */
|
||||
#define MSR_UIE PPC_BIT_NR(47) /* Unmaskable Interrupt Enable (PPE42) */
|
||||
#define MSR_EE PPC_BIT_NR(48) /* External interrupt enable */
|
||||
#define MSR_PR PPC_BIT_NR(49) /* Problem state hflags */
|
||||
#define MSR_FP PPC_BIT_NR(50) /* Floating point available hflags */
|
||||
#define MSR_ME PPC_BIT_NR(51) /* Machine check interrupt enable */
|
||||
#define MSR_FE0 PPC_BIT_NR(52) /* Floating point exception mode 0 */
|
||||
#define MSR_IS2 PPC_BIT_NR(52) /* Instance Specific Bit 2 (PPE42) */
|
||||
#define MSR_IS3 PPC_BIT_NR(53) /* Instance Specific Bit 3 (PPE42) */
|
||||
#define MSR_SE PPC_BIT_NR(53) /* Single-step trace enable x hflags */
|
||||
#define MSR_DWE PPC_BIT_NR(53) /* Debug wait enable on 405 x */
|
||||
#define MSR_UBLE PPC_BIT_NR(53) /* User BTB lock enable on e500 x */
|
||||
#define MSR_BE PPC_BIT_NR(54) /* Branch trace enable x hflags */
|
||||
#define MSR_DE PPC_BIT_NR(54) /* Debug int. enable on embedded PPC x */
|
||||
#define MSR_FE1 PPC_BIT_NR(55) /* Floating point exception mode 1 */
|
||||
#define MSR_IPE PPC_BIT_NR(55) /* Imprecise Mode Enable (PPE42) */
|
||||
#define MSR_AL PPC_BIT_NR(56) /* AL bit on POWER */
|
||||
#define MSR_SIBRCA0 PPC_BIT_NR(56) /* SIB Return Code Accumulator 0 (PPE42) */
|
||||
#define MSR_SIBRCA1 PPC_BIT_NR(57) /* SIB Return Code Accumulator 1 (PPE42) */
|
||||
#define MSR_EP PPC_BIT_NR(57) /* Exception prefix on 601 */
|
||||
#define MSR_IR PPC_BIT_NR(58) /* Instruction relocate */
|
||||
#define MSR_IS PPC_BIT_NR(58) /* Instruction address space (BookE) */
|
||||
#define MSR_SIBRCA2 PPC_BIT_NR(58) /* SIB Return Code Accumulator 2 (PPE42) */
|
||||
#define MSR_SIBRCA3 PPC_BIT_NR(59) /* SIB Return Code Accumulator 3 (PPE42) */
|
||||
#define MSR_DR PPC_BIT_NR(59) /* Data relocate */
|
||||
#define MSR_DS PPC_BIT_NR(59) /* Data address space (BookE) */
|
||||
#define MSR_PE PPC_BIT_NR(60) /* Protection enable on 403 */
|
||||
#define MSR_SIBRCA4 PPC_BIT_NR(60) /* SIB Return Code Accumulator 4 (PPE42) */
|
||||
#define MSR_SIBRCA5 PPC_BIT_NR(61) /* SIB Return Code Accumulator 5 (PPE42) */
|
||||
#define MSR_PX PPC_BIT_NR(61) /* Protection exclusive on 403 x */
|
||||
#define MSR_PMM PPC_BIT_NR(61) /* Performance monitor mark on POWER x */
|
||||
#define MSR_RI PPC_BIT_NR(62) /* Recoverable interrupt 1 */
|
||||
#define MSR_SIBRCA6 PPC_BIT_NR(62) /* SIB Return Code Accumulator 6 (PPE42) */
|
||||
#define MSR_SIBRCA7 PPC_BIT_NR(63) /* SIB Return Code Accumulator 7 (PPE42) */
|
||||
#define MSR_LE PPC_BIT_NR(63) /* Little-endian mode 1 hflags */
|
||||
|
||||
FIELD(MSR, SF, MSR_SF, 1)
|
||||
@@ -517,6 +546,9 @@ FIELD(MSR, PX, MSR_PX, 1)
|
||||
FIELD(MSR, PMM, MSR_PMM, 1)
|
||||
FIELD(MSR, RI, MSR_RI, 1)
|
||||
FIELD(MSR, LE, MSR_LE, 1)
|
||||
FIELD(MSR, SEM, MSR_SEM6, 7)
|
||||
FIELD(MSR, SIBRC, MSR_SIBRC2, 3)
|
||||
FIELD(MSR, SIBRCA, MSR_SIBRCA7, 8)
|
||||
|
||||
/*
|
||||
* FE0 and FE1 bits are not side-by-side
|
||||
@@ -730,6 +762,31 @@ FIELD(MSR, LE, MSR_LE, 1)
|
||||
#define ESR_VLEMI PPC_BIT(58) /* VLE operation */
|
||||
#define ESR_MIF PPC_BIT(62) /* Misaligned instruction (VLE) */
|
||||
|
||||
/* PPE42 Interrupt Status Register bits */
|
||||
#define PPE42_ISR_SRSMS0 PPC_BIT_NR(48) /* Sys Reset State Machine State 0 */
|
||||
#define PPE42_ISR_SRSMS1 PPC_BIT_NR(49) /* Sys Reset State Machine State 1 */
|
||||
#define PPE42_ISR_SRSMS2 PPC_BIT_NR(50) /* Sys Reset State Machine State 2 */
|
||||
#define PPE42_ISR_SRSMS3 PPC_BIT_NR(51) /* Sys Reset State Machine State 3 */
|
||||
#define PPE42_ISR_EP PPC_BIT_NR(53) /* MSR[EE] Maskable Event Pending */
|
||||
#define PPE42_ISR_PTR PPC_BIT_NR(56) /* Program Interrupt from trap */
|
||||
#define PPE42_ISR_ST PPC_BIT_NR(57) /* Data Interrupt caused by store */
|
||||
#define PPE42_ISR_MFE PPC_BIT_NR(60) /* Multiple Fault Error */
|
||||
#define PPE42_ISR_MCS0 PPC_BIT_NR(61) /* Machine Check Status bit0 */
|
||||
#define PPE42_ISR_MCS1 PPC_BIT_NR(62) /* Machine Check Status bit1 */
|
||||
#define PPE42_ISR_MCS2 PPC_BIT_NR(63) /* Machine Check Status bit2 */
|
||||
FIELD(PPE42_ISR, SRSMS, PPE42_ISR_SRSMS3, 4)
|
||||
FIELD(PPE42_ISR, MCS, PPE42_ISR_MCS2, 3)
|
||||
|
||||
/* PPE42 Machine Check Status field values */
|
||||
#define PPE42_ISR_MCS_INSTRUCTION 0
|
||||
#define PPE42_ISR_MCS_DATA_LOAD 1
|
||||
#define PPE42_ISR_MCS_DATA_PRECISE_STORE 2
|
||||
#define PPE42_ISR_MCS_DATA_IMPRECISE_STORE 3
|
||||
#define PPE42_ISR_MCS_PROGRAM 4
|
||||
#define PPE42_ISR_MCS_ISI 5
|
||||
#define PPE42_ISR_MCS_ALIGNMENT 6
|
||||
#define PPE42_ISR_MCS_DSI 7
|
||||
|
||||
/* Transaction EXception And Summary Register bits */
|
||||
#define TEXASR_FAILURE_PERSISTENT (63 - 7)
|
||||
#define TEXASR_DISALLOWED (63 - 8)
|
||||
@@ -785,6 +842,8 @@ enum {
|
||||
POWERPC_FLAG_SMT_1LPAR = 0x00800000,
|
||||
/* Has BHRB */
|
||||
POWERPC_FLAG_BHRB = 0x01000000,
|
||||
/* Use PPE42-specific behavior */
|
||||
POWERPC_FLAG_PPE42 = 0x02000000,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1754,9 +1813,12 @@ void ppc_compat_add_property(Object *obj, const char *name,
|
||||
#define SPR_BOOKE_CSRR0 (0x03A)
|
||||
#define SPR_BOOKE_CSRR1 (0x03B)
|
||||
#define SPR_BOOKE_DEAR (0x03D)
|
||||
#define SPR_PPE42_EDR (0x03D)
|
||||
#define SPR_IAMR (0x03D)
|
||||
#define SPR_BOOKE_ESR (0x03E)
|
||||
#define SPR_PPE42_ISR (0x03E)
|
||||
#define SPR_BOOKE_IVPR (0x03F)
|
||||
#define SPR_PPE42_IVPR (0x03F)
|
||||
#define SPR_MPC_EIE (0x050)
|
||||
#define SPR_MPC_EID (0x051)
|
||||
#define SPR_MPC_NRI (0x052)
|
||||
@@ -1822,6 +1884,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
|
||||
#define SPR_TBU40 (0x11E)
|
||||
#define SPR_SVR (0x11E)
|
||||
#define SPR_BOOKE_PIR (0x11E)
|
||||
#define SPR_PPE42_PIR (0x11E)
|
||||
#define SPR_PVR (0x11F)
|
||||
#define SPR_HSPRG0 (0x130)
|
||||
#define SPR_BOOKE_DBSR (0x130)
|
||||
@@ -1831,6 +1894,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
|
||||
#define SPR_BOOKE_EPCR (0x133)
|
||||
#define SPR_SPURR (0x134)
|
||||
#define SPR_BOOKE_DBCR0 (0x134)
|
||||
#define SPR_PPE42_DBCR (0x134)
|
||||
#define SPR_IBCR (0x135)
|
||||
#define SPR_PURR (0x135)
|
||||
#define SPR_BOOKE_DBCR1 (0x135)
|
||||
@@ -1848,6 +1912,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
|
||||
#define SPR_HSRR1 (0x13B)
|
||||
#define SPR_BOOKE_IAC4 (0x13B)
|
||||
#define SPR_BOOKE_DAC1 (0x13C)
|
||||
#define SPR_PPE42_DACR (0x13C)
|
||||
#define SPR_MMCRH (0x13C)
|
||||
#define SPR_DABR2 (0x13D)
|
||||
#define SPR_BOOKE_DAC2 (0x13D)
|
||||
@@ -1857,12 +1922,14 @@ void ppc_compat_add_property(Object *obj, const char *name,
|
||||
#define SPR_BOOKE_DVC2 (0x13F)
|
||||
#define SPR_LPIDR (0x13F)
|
||||
#define SPR_BOOKE_TSR (0x150)
|
||||
#define SPR_PPE42_TSR (0x150)
|
||||
#define SPR_HMER (0x150)
|
||||
#define SPR_HMEER (0x151)
|
||||
#define SPR_PCR (0x152)
|
||||
#define SPR_HEIR (0x153)
|
||||
#define SPR_BOOKE_LPIDR (0x152)
|
||||
#define SPR_BOOKE_TCR (0x154)
|
||||
#define SPR_PPE42_TCR (0x154)
|
||||
#define SPR_BOOKE_TLB0PS (0x158)
|
||||
#define SPR_BOOKE_TLB1PS (0x159)
|
||||
#define SPR_BOOKE_TLB2PS (0x15A)
|
||||
@@ -2532,6 +2599,12 @@ enum {
|
||||
PPC2_MEM_LWSYNC = 0x0000000000200000ULL,
|
||||
/* ISA 2.06 BCD assist instructions */
|
||||
PPC2_BCDA_ISA206 = 0x0000000000400000ULL,
|
||||
/* PPE42 instructions */
|
||||
PPC2_PPE42 = 0x0000000000800000ULL,
|
||||
/* PPE42X instructions */
|
||||
PPC2_PPE42X = 0x0000000001000000ULL,
|
||||
/* PPE42XM instructions */
|
||||
PPC2_PPE42XM = 0x0000000002000000ULL,
|
||||
|
||||
#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \
|
||||
PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
|
||||
@@ -2541,7 +2614,8 @@ enum {
|
||||
PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \
|
||||
PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206 | \
|
||||
PPC2_ISA300 | PPC2_ISA310 | PPC2_MEM_LWSYNC | \
|
||||
PPC2_BCDA_ISA206)
|
||||
PPC2_BCDA_ISA206 | PPC2_PPE42 | PPC2_PPE42X | \
|
||||
PPC2_PPE42XM)
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
+212
-39
@@ -1653,6 +1653,47 @@ static void register_8xx_sprs(CPUPPCState *env)
|
||||
* ... and more (thermal management, performance counters, ...)
|
||||
*/
|
||||
|
||||
static void register_ppe42_sprs(CPUPPCState *env)
|
||||
{
|
||||
spr_register(env, SPR_PPE42_EDR, "EDR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_PPE42_ISR, "ISR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_PPE42_IVPR, "IVPR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
0xfff80000);
|
||||
spr_register(env, SPR_PPE42_PIR, "PIR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_pir,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_PPE42_DBCR, "DBCR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_40x_dbcr0,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_PPE42_DACR, "DACR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* Timer */
|
||||
spr_register(env, SPR_DECR, "DECR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_decr, &spr_write_decr,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_PPE42_TSR, "TSR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_booke_tsr,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_BOOKE_TCR, "TCR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_booke_tcr,
|
||||
0x00000000);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Exception vectors models */
|
||||
static void init_excp_4xx(CPUPPCState *env)
|
||||
@@ -1679,6 +1720,30 @@ static void init_excp_4xx(CPUPPCState *env)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void init_excp_ppe42(CPUPPCState *env)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* Machine Check vector changed after version 0 */
|
||||
if (((env->spr[SPR_PVR] & 0xf00000ul) >> 20) == 0) {
|
||||
env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000000;
|
||||
} else {
|
||||
env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000020;
|
||||
}
|
||||
env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000040;
|
||||
env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000060;
|
||||
env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000080;
|
||||
env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x000000A0;
|
||||
env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x000000C0;
|
||||
env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x000000E0;
|
||||
env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000100;
|
||||
env->excp_vectors[POWERPC_EXCP_FIT] = 0x00000120;
|
||||
env->excp_vectors[POWERPC_EXCP_WDT] = 0x00000140;
|
||||
env->ivpr_mask = 0xFFFFFE00UL;
|
||||
/* Hardware reset vector */
|
||||
env->hreset_vector = 0x00000040UL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void init_excp_MPC5xx(CPUPPCState *env)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
@@ -2200,6 +2265,80 @@ POWERPC_FAMILY(405)(ObjectClass *oc, const void *data)
|
||||
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
|
||||
}
|
||||
|
||||
static void init_proc_ppe42(CPUPPCState *env)
|
||||
{
|
||||
register_ppe42_sprs(env);
|
||||
|
||||
init_excp_ppe42(env);
|
||||
env->dcache_line_size = 32;
|
||||
env->icache_line_size = 32;
|
||||
/* Allocate hardware IRQ controller */
|
||||
ppc40x_irq_init(env_archcpu(env));
|
||||
|
||||
SET_FIT_PERIOD(8, 12, 16, 20);
|
||||
SET_WDT_PERIOD(16, 20, 24, 28);
|
||||
}
|
||||
|
||||
static void ppe42_class_common_init(PowerPCCPUClass *pcc)
|
||||
{
|
||||
pcc->init_proc = init_proc_ppe42;
|
||||
pcc->check_pow = check_pow_nocheck;
|
||||
pcc->check_attn = check_attn_none;
|
||||
pcc->insns_flags = PPC_INSNS_BASE |
|
||||
PPC_WRTEE |
|
||||
PPC_CACHE |
|
||||
PPC_CACHE_DCBZ |
|
||||
PPC_MEM_SYNC;
|
||||
pcc->msr_mask = R_MSR_SEM_MASK |
|
||||
(1ull << MSR_IS0) |
|
||||
R_MSR_SIBRC_MASK |
|
||||
(1ull << MSR_LP) |
|
||||
(1ull << MSR_WE) |
|
||||
(1ull << MSR_IS1) |
|
||||
(1ull << MSR_UIE) |
|
||||
(1ull << MSR_EE) |
|
||||
(1ull << MSR_ME) |
|
||||
(1ull << MSR_IS2) |
|
||||
(1ull << MSR_IS3) |
|
||||
(1ull << MSR_IPE) |
|
||||
R_MSR_SIBRCA_MASK;
|
||||
pcc->mmu_model = POWERPC_MMU_REAL;
|
||||
pcc->excp_model = POWERPC_EXCP_PPE42;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_PPE42;
|
||||
pcc->bfd_mach = bfd_mach_ppc_403;
|
||||
pcc->flags = POWERPC_FLAG_PPE42 | POWERPC_FLAG_BUS_CLK;
|
||||
}
|
||||
|
||||
POWERPC_FAMILY(ppe42)(ObjectClass *oc, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
|
||||
dc->desc = "PPE 42";
|
||||
pcc->insns_flags2 = PPC2_PPE42;
|
||||
ppe42_class_common_init(pcc);
|
||||
}
|
||||
|
||||
POWERPC_FAMILY(ppe42x)(ObjectClass *oc, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
|
||||
dc->desc = "PPE 42X";
|
||||
pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X;
|
||||
ppe42_class_common_init(pcc);
|
||||
}
|
||||
|
||||
POWERPC_FAMILY(ppe42xm)(ObjectClass *oc, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
|
||||
dc->desc = "PPE 42XM";
|
||||
pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X | PPC2_PPE42XM;
|
||||
ppe42_class_common_init(pcc);
|
||||
}
|
||||
|
||||
static void init_proc_440EP(CPUPPCState *env)
|
||||
{
|
||||
register_BookE_sprs(env, 0x000000000000FFFFULL);
|
||||
@@ -6802,53 +6941,64 @@ static void init_ppc_proc(PowerPCCPU *cpu)
|
||||
|
||||
/* MSR bits & flags consistency checks */
|
||||
if (env->msr_mask & (1 << 25)) {
|
||||
switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) {
|
||||
switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE |
|
||||
POWERPC_FLAG_PPE42)) {
|
||||
case POWERPC_FLAG_SPE:
|
||||
case POWERPC_FLAG_VRE:
|
||||
case POWERPC_FLAG_PPE42:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "PowerPC MSR definition inconsistency\n"
|
||||
"Should define POWERPC_FLAG_SPE or POWERPC_FLAG_VRE\n");
|
||||
"Should define POWERPC_FLAG_SPE or POWERPC_FLAG_VRE\n"
|
||||
"or POWERPC_FLAG_PPE42\n");
|
||||
exit(1);
|
||||
}
|
||||
} else if (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) {
|
||||
} else if (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE |
|
||||
POWERPC_FLAG_PPE42)) {
|
||||
fprintf(stderr, "PowerPC MSR definition inconsistency\n"
|
||||
"Should not define POWERPC_FLAG_SPE nor POWERPC_FLAG_VRE\n");
|
||||
"Should not define POWERPC_FLAG_SPE nor POWERPC_FLAG_VRE\n"
|
||||
"nor POWERPC_FLAG_PPE42\n");
|
||||
exit(1);
|
||||
}
|
||||
if (env->msr_mask & (1 << 17)) {
|
||||
switch (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE)) {
|
||||
switch (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE |
|
||||
POWERPC_FLAG_PPE42)) {
|
||||
case POWERPC_FLAG_TGPR:
|
||||
case POWERPC_FLAG_CE:
|
||||
case POWERPC_FLAG_PPE42:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "PowerPC MSR definition inconsistency\n"
|
||||
"Should define POWERPC_FLAG_TGPR or POWERPC_FLAG_CE\n");
|
||||
"Should define POWERPC_FLAG_TGPR or POWERPC_FLAG_CE\n"
|
||||
"or POWERPC_FLAG_PPE42\n");
|
||||
exit(1);
|
||||
}
|
||||
} else if (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE)) {
|
||||
} else if (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE |
|
||||
POWERPC_FLAG_PPE42)) {
|
||||
fprintf(stderr, "PowerPC MSR definition inconsistency\n"
|
||||
"Should not define POWERPC_FLAG_TGPR nor POWERPC_FLAG_CE\n");
|
||||
"Should not define POWERPC_FLAG_TGPR nor POWERPC_FLAG_CE\n"
|
||||
"nor POWERPC_FLAG_PPE42\n");
|
||||
exit(1);
|
||||
}
|
||||
if (env->msr_mask & (1 << 10)) {
|
||||
switch (env->flags & (POWERPC_FLAG_SE | POWERPC_FLAG_DWE |
|
||||
POWERPC_FLAG_UBLE)) {
|
||||
POWERPC_FLAG_UBLE | POWERPC_FLAG_PPE42)) {
|
||||
case POWERPC_FLAG_SE:
|
||||
case POWERPC_FLAG_DWE:
|
||||
case POWERPC_FLAG_UBLE:
|
||||
case POWERPC_FLAG_PPE42:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "PowerPC MSR definition inconsistency\n"
|
||||
"Should define POWERPC_FLAG_SE or POWERPC_FLAG_DWE or "
|
||||
"POWERPC_FLAG_UBLE\n");
|
||||
"POWERPC_FLAG_UBLE or POWERPC_FLAG_PPE42\n");
|
||||
exit(1);
|
||||
}
|
||||
} else if (env->flags & (POWERPC_FLAG_SE | POWERPC_FLAG_DWE |
|
||||
POWERPC_FLAG_UBLE)) {
|
||||
POWERPC_FLAG_UBLE | POWERPC_FLAG_PPE42)) {
|
||||
fprintf(stderr, "PowerPC MSR definition inconsistency\n"
|
||||
"Should not define POWERPC_FLAG_SE nor POWERPC_FLAG_DWE nor "
|
||||
"POWERPC_FLAG_UBLE\n");
|
||||
"POWERPC_FLAG_UBLE nor POWERPC_FLAG_PPE42\n");
|
||||
exit(1);
|
||||
}
|
||||
if (env->msr_mask & (1 << 9)) {
|
||||
@@ -6867,18 +7017,23 @@ static void init_ppc_proc(PowerPCCPU *cpu)
|
||||
exit(1);
|
||||
}
|
||||
if (env->msr_mask & (1 << 2)) {
|
||||
switch (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM)) {
|
||||
switch (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM |
|
||||
POWERPC_FLAG_PPE42)) {
|
||||
case POWERPC_FLAG_PX:
|
||||
case POWERPC_FLAG_PMM:
|
||||
case POWERPC_FLAG_PPE42:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "PowerPC MSR definition inconsistency\n"
|
||||
"Should define POWERPC_FLAG_PX or POWERPC_FLAG_PMM\n");
|
||||
"Should define POWERPC_FLAG_PX or POWERPC_FLAG_PMM\n"
|
||||
"or POWERPC_FLAG_PPE42\n");
|
||||
exit(1);
|
||||
}
|
||||
} else if (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM)) {
|
||||
} else if (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM |
|
||||
POWERPC_FLAG_PPE42)) {
|
||||
fprintf(stderr, "PowerPC MSR definition inconsistency\n"
|
||||
"Should not define POWERPC_FLAG_PX nor POWERPC_FLAG_PMM\n");
|
||||
"Should not define POWERPC_FLAG_PX nor POWERPC_FLAG_PMM\n"
|
||||
"nor POWERPC_FLAG_PPE42\n");
|
||||
exit(1);
|
||||
}
|
||||
if ((env->flags & POWERPC_FLAG_BUS_CLK) == 0) {
|
||||
@@ -7143,6 +7298,7 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data)
|
||||
{
|
||||
ObjectClass *oc = data;
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
CPUClass *cc = CPU_CLASS(oc);
|
||||
DeviceClass *family = DEVICE_CLASS(ppc_cpu_get_family_class(pcc));
|
||||
const char *typename = object_class_get_name(oc);
|
||||
char *name;
|
||||
@@ -7153,7 +7309,11 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data)
|
||||
}
|
||||
|
||||
name = cpu_model_from_type(typename);
|
||||
qemu_printf(" %-16s PVR %08x\n", name, pcc->pvr);
|
||||
if (cc->deprecation_note) {
|
||||
qemu_printf(" %-16s PVR %08x (deprecated)\n", name, pcc->pvr);
|
||||
} else {
|
||||
qemu_printf(" %-16s PVR %08x\n", name, pcc->pvr);
|
||||
}
|
||||
for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
|
||||
PowerPCCPUAlias *alias = &ppc_cpu_aliases[i];
|
||||
ObjectClass *alias_oc = ppc_cpu_class_by_name(alias->model);
|
||||
@@ -7243,39 +7403,40 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
|
||||
}
|
||||
|
||||
msr = (target_ulong)0;
|
||||
msr |= (target_ulong)MSR_HVB;
|
||||
msr |= (target_ulong)1 << MSR_EP;
|
||||
if (!(env->flags & POWERPC_FLAG_PPE42)) {
|
||||
msr |= (target_ulong)MSR_HVB;
|
||||
msr |= (target_ulong)1 << MSR_EP;
|
||||
#if defined(DO_SINGLE_STEP) && 0
|
||||
/* Single step trace mode */
|
||||
msr |= (target_ulong)1 << MSR_SE;
|
||||
msr |= (target_ulong)1 << MSR_BE;
|
||||
/* Single step trace mode */
|
||||
msr |= (target_ulong)1 << MSR_SE;
|
||||
msr |= (target_ulong)1 << MSR_BE;
|
||||
#endif
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
|
||||
msr |= (target_ulong)1 << MSR_FE0; /* Allow floating point exceptions */
|
||||
msr |= (target_ulong)1 << MSR_FE1;
|
||||
msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
|
||||
msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */
|
||||
msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
|
||||
msr |= (target_ulong)1 << MSR_PR;
|
||||
msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
|
||||
msr |= (target_ulong)1 << MSR_FE0; /* Allow floating point exceptions */
|
||||
msr |= (target_ulong)1 << MSR_FE1;
|
||||
msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
|
||||
msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */
|
||||
msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
|
||||
msr |= (target_ulong)1 << MSR_PR;
|
||||
#if defined(TARGET_PPC64)
|
||||
msr |= (target_ulong)1 << MSR_TM; /* Transactional memory */
|
||||
msr |= (target_ulong)1 << MSR_TM; /* Transactional memory */
|
||||
#endif
|
||||
#if !TARGET_BIG_ENDIAN
|
||||
msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */
|
||||
if (!((env->msr_mask >> MSR_LE) & 1)) {
|
||||
fprintf(stderr, "Selected CPU does not support little-endian.\n");
|
||||
exit(1);
|
||||
}
|
||||
msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */
|
||||
if (!((env->msr_mask >> MSR_LE) & 1)) {
|
||||
fprintf(stderr, "Selected CPU does not support little-endian.\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
if (mmu_is_64bit(env->mmu_model)) {
|
||||
msr |= (1ULL << MSR_SF);
|
||||
}
|
||||
if (mmu_is_64bit(env->mmu_model)) {
|
||||
msr |= (1ULL << MSR_SF);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
hreg_store_msr(env, msr, 1);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
@@ -7725,6 +7886,18 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
* they can be read with "p $ivor0", "p $ivor1", etc.
|
||||
*/
|
||||
break;
|
||||
case POWERPC_EXCP_PPE42:
|
||||
qemu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
|
||||
|
||||
qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
|
||||
" ISR " TARGET_FMT_lx " EDR " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_PPE42_TCR], env->spr[SPR_PPE42_TSR],
|
||||
env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
|
||||
|
||||
qemu_fprintf(f, " PIR " TARGET_FMT_lx " IVPR " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_PPE42_PIR], env->spr[SPR_PPE42_IVPR]);
|
||||
break;
|
||||
case POWERPC_EXCP_40x:
|
||||
qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
|
||||
" ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n",
|
||||
|
||||
@@ -949,6 +949,125 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
|
||||
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||
}
|
||||
|
||||
static void powerpc_excp_ppe42(PowerPCCPU *cpu, int excp)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong msr, new_msr, vector;
|
||||
target_ulong mcs = PPE42_ISR_MCS_INSTRUCTION;
|
||||
bool promote_unmaskable;
|
||||
|
||||
msr = env->msr;
|
||||
|
||||
/*
|
||||
* New interrupt handler msr preserves SIBRC and ME unless explicitly
|
||||
* overridden by the exception. All other MSR bits are zeroed out.
|
||||
*/
|
||||
new_msr = env->msr & (((target_ulong)1 << MSR_ME) | R_MSR_SIBRC_MASK);
|
||||
|
||||
/* HV emu assistance interrupt only exists on server arch 2.05 or later */
|
||||
if (excp == POWERPC_EXCP_HV_EMU) {
|
||||
excp = POWERPC_EXCP_PROGRAM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmaskable interrupts (Program, ISI, Alignment and DSI) are promoted to
|
||||
* machine check if MSR_UIE is 0.
|
||||
*/
|
||||
promote_unmaskable = !(msr & ((target_ulong)1 << MSR_UIE));
|
||||
|
||||
|
||||
switch (excp) {
|
||||
case POWERPC_EXCP_MCHECK: /* Machine check exception */
|
||||
break;
|
||||
case POWERPC_EXCP_DSI: /* Data storage exception */
|
||||
trace_ppc_excp_dsi(env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
|
||||
if (promote_unmaskable) {
|
||||
excp = POWERPC_EXCP_MCHECK;
|
||||
mcs = PPE42_ISR_MCS_DSI;
|
||||
}
|
||||
break;
|
||||
case POWERPC_EXCP_ISI: /* Instruction storage exception */
|
||||
trace_ppc_excp_isi(msr, env->nip);
|
||||
if (promote_unmaskable) {
|
||||
excp = POWERPC_EXCP_MCHECK;
|
||||
mcs = PPE42_ISR_MCS_ISI;
|
||||
}
|
||||
break;
|
||||
case POWERPC_EXCP_EXTERNAL: /* External input */
|
||||
break;
|
||||
case POWERPC_EXCP_ALIGN: /* Alignment exception */
|
||||
if (promote_unmaskable) {
|
||||
excp = POWERPC_EXCP_MCHECK;
|
||||
mcs = PPE42_ISR_MCS_ALIGNMENT;
|
||||
}
|
||||
break;
|
||||
case POWERPC_EXCP_PROGRAM: /* Program exception */
|
||||
if (promote_unmaskable) {
|
||||
excp = POWERPC_EXCP_MCHECK;
|
||||
mcs = PPE42_ISR_MCS_PROGRAM;
|
||||
}
|
||||
switch (env->error_code & ~0xF) {
|
||||
case POWERPC_EXCP_INVAL:
|
||||
trace_ppc_excp_inval(env->nip);
|
||||
env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_PTR);
|
||||
break;
|
||||
case POWERPC_EXCP_TRAP:
|
||||
env->spr[SPR_PPE42_ISR] |= ((target_ulong)1 << PPE42_ISR_PTR);
|
||||
break;
|
||||
default:
|
||||
/* Should never occur */
|
||||
cpu_abort(env_cpu(env), "Invalid program exception %d. Aborting\n",
|
||||
env->error_code);
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_TCG
|
||||
env->spr[SPR_PPE42_EDR] = ppc_ldl_code(env, env->nip);
|
||||
#endif
|
||||
break;
|
||||
case POWERPC_EXCP_DECR: /* Decrementer exception */
|
||||
break;
|
||||
case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
|
||||
trace_ppc_excp_print("FIT");
|
||||
break;
|
||||
case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
|
||||
trace_ppc_excp_print("WDT");
|
||||
break;
|
||||
case POWERPC_EXCP_RESET: /* System reset exception */
|
||||
/* reset exceptions don't have ME set */
|
||||
new_msr &= ~((target_ulong)1 << MSR_ME);
|
||||
break;
|
||||
default:
|
||||
cpu_abort(env_cpu(env), "Invalid PPE42 exception %d. Aborting\n",
|
||||
excp);
|
||||
break;
|
||||
}
|
||||
|
||||
env->spr[SPR_SRR0] = env->nip;
|
||||
env->spr[SPR_SRR1] = msr;
|
||||
|
||||
vector = env->excp_vectors[excp];
|
||||
if (vector == (target_ulong)-1ULL) {
|
||||
cpu_abort(env_cpu(env),
|
||||
"Raised an exception without defined vector %d\n", excp);
|
||||
}
|
||||
vector |= env->spr[SPR_PPE42_IVPR];
|
||||
|
||||
if (excp == POWERPC_EXCP_MCHECK) {
|
||||
/* Also set the Machine Check Status (MCS) */
|
||||
env->spr[SPR_PPE42_ISR] &= ~R_PPE42_ISR_MCS_MASK;
|
||||
env->spr[SPR_PPE42_ISR] |= (mcs & R_PPE42_ISR_MCS_MASK);
|
||||
env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_MFE);
|
||||
|
||||
/* Machine checks halt execution if MSR_ME is 0 */
|
||||
powerpc_mcheck_checkstop(env);
|
||||
|
||||
/* machine check exceptions don't have ME set */
|
||||
new_msr &= ~((target_ulong)1 << MSR_ME);
|
||||
}
|
||||
|
||||
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||
}
|
||||
|
||||
static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
@@ -1589,6 +1708,9 @@ void powerpc_excp(PowerPCCPU *cpu, int excp)
|
||||
case POWERPC_EXCP_POWER11:
|
||||
powerpc_excp_books(cpu, excp);
|
||||
break;
|
||||
case POWERPC_EXCP_PPE42:
|
||||
powerpc_excp_ppe42(cpu, excp);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
@@ -1945,6 +2067,43 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env,
|
||||
}
|
||||
#endif /* TARGET_PPC64 */
|
||||
|
||||
static int ppe42_next_unmasked_interrupt(CPUPPCState *env)
|
||||
{
|
||||
bool async_deliver;
|
||||
|
||||
/* External reset */
|
||||
if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
|
||||
return PPC_INTERRUPT_RESET;
|
||||
}
|
||||
/* Machine check exception */
|
||||
if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
|
||||
return PPC_INTERRUPT_MCK;
|
||||
}
|
||||
|
||||
async_deliver = FIELD_EX64(env->msr, MSR, EE);
|
||||
|
||||
if (async_deliver != 0) {
|
||||
/* Watchdog timer */
|
||||
if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
|
||||
return PPC_INTERRUPT_WDT;
|
||||
}
|
||||
/* External Interrupt */
|
||||
if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
|
||||
return PPC_INTERRUPT_EXT;
|
||||
}
|
||||
/* Fixed interval timer */
|
||||
if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
|
||||
return PPC_INTERRUPT_FIT;
|
||||
}
|
||||
/* Decrementer exception */
|
||||
if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
|
||||
return PPC_INTERRUPT_DECR;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ppc_next_unmasked_interrupt(CPUPPCState *env)
|
||||
{
|
||||
uint32_t pending_interrupts = env->pending_interrupts;
|
||||
@@ -1970,6 +2129,10 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (env->excp_model == POWERPC_EXCP_PPE42) {
|
||||
return ppe42_next_unmasked_interrupt(env);
|
||||
}
|
||||
|
||||
/* External reset */
|
||||
if (pending_interrupts & PPC_INTERRUPT_RESET) {
|
||||
return PPC_INTERRUPT_RESET;
|
||||
|
||||
+19
-19
@@ -562,14 +562,14 @@ uint64_t helper_##op(CPUPPCState *env, float64 arg) \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
FPU_FCTI(fctiw, int32, 0x80000000U)
|
||||
FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U)
|
||||
FPU_FCTI(fctiwu, uint32, 0x00000000U)
|
||||
FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U)
|
||||
FPU_FCTI(fctid, int64, 0x8000000000000000ULL)
|
||||
FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL)
|
||||
FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL)
|
||||
FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL)
|
||||
FPU_FCTI(FCTIW, int32, 0x80000000U)
|
||||
FPU_FCTI(FCTIWZ, int32_round_to_zero, 0x80000000U)
|
||||
FPU_FCTI(FCTIWU, uint32, 0x00000000U)
|
||||
FPU_FCTI(FCTIWUZ, uint32_round_to_zero, 0x00000000U)
|
||||
FPU_FCTI(FCTID, int64, 0x8000000000000000ULL)
|
||||
FPU_FCTI(FCTIDZ, int64_round_to_zero, 0x8000000000000000ULL)
|
||||
FPU_FCTI(FCTIDU, uint64, 0x0000000000000000ULL)
|
||||
FPU_FCTI(FCTIDUZ, uint64_round_to_zero, 0x0000000000000000ULL)
|
||||
|
||||
#define FPU_FCFI(op, cvtr, is_single) \
|
||||
uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \
|
||||
@@ -586,10 +586,10 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \
|
||||
return farg.ll; \
|
||||
}
|
||||
|
||||
FPU_FCFI(fcfid, int64_to_float64, 0)
|
||||
FPU_FCFI(fcfids, int64_to_float32, 1)
|
||||
FPU_FCFI(fcfidu, uint64_to_float64, 0)
|
||||
FPU_FCFI(fcfidus, uint64_to_float32, 1)
|
||||
FPU_FCFI(FCFID, int64_to_float64, 0)
|
||||
FPU_FCFI(FCFIDS, int64_to_float32, 1)
|
||||
FPU_FCFI(FCFIDU, uint64_to_float64, 0)
|
||||
FPU_FCFI(FCFIDUS, uint64_to_float32, 1)
|
||||
|
||||
static uint64_t do_fri(CPUPPCState *env, uint64_t arg,
|
||||
FloatRoundMode rounding_mode)
|
||||
@@ -613,22 +613,22 @@ static uint64_t do_fri(CPUPPCState *env, uint64_t arg,
|
||||
return arg;
|
||||
}
|
||||
|
||||
uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
|
||||
uint64_t helper_FRIN(CPUPPCState *env, uint64_t arg)
|
||||
{
|
||||
return do_fri(env, arg, float_round_ties_away);
|
||||
}
|
||||
|
||||
uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
|
||||
uint64_t helper_FRIZ(CPUPPCState *env, uint64_t arg)
|
||||
{
|
||||
return do_fri(env, arg, float_round_to_zero);
|
||||
}
|
||||
|
||||
uint64_t helper_frip(CPUPPCState *env, uint64_t arg)
|
||||
uint64_t helper_FRIP(CPUPPCState *env, uint64_t arg)
|
||||
{
|
||||
return do_fri(env, arg, float_round_up);
|
||||
}
|
||||
|
||||
uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
|
||||
uint64_t helper_FRIM(CPUPPCState *env, uint64_t arg)
|
||||
{
|
||||
return do_fri(env, arg, float_round_down);
|
||||
}
|
||||
@@ -697,7 +697,7 @@ static uint64_t do_frsp(CPUPPCState *env, uint64_t arg, uintptr_t retaddr)
|
||||
return helper_todouble(f32);
|
||||
}
|
||||
|
||||
uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
|
||||
uint64_t helper_FRSP(CPUPPCState *env, uint64_t arg)
|
||||
{
|
||||
return do_frsp(env, arg, GETPC());
|
||||
}
|
||||
@@ -871,7 +871,7 @@ uint32_t helper_FTSQRT(uint64_t frb)
|
||||
return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0);
|
||||
}
|
||||
|
||||
void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
||||
void helper_FCMPU(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
||||
uint32_t crfD)
|
||||
{
|
||||
CPU_DoubleU farg1, farg2;
|
||||
@@ -902,7 +902,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
||||
}
|
||||
}
|
||||
|
||||
void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
||||
void helper_FCMPO(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
||||
uint32_t crfD)
|
||||
{
|
||||
CPU_DoubleU farg1, farg2;
|
||||
|
||||
+19
-19
@@ -94,26 +94,26 @@ DEF_HELPER_2(fpscr_setbit, void, env, i32)
|
||||
DEF_HELPER_FLAGS_1(todouble, TCG_CALL_NO_RWG_SE, i64, i32)
|
||||
DEF_HELPER_FLAGS_1(tosingle, TCG_CALL_NO_RWG_SE, i32, i64)
|
||||
|
||||
DEF_HELPER_4(fcmpo, void, env, i64, i64, i32)
|
||||
DEF_HELPER_4(fcmpu, void, env, i64, i64, i32)
|
||||
DEF_HELPER_4(FCMPO, void, env, i64, i64, i32)
|
||||
DEF_HELPER_4(FCMPU, void, env, i64, i64, i32)
|
||||
|
||||
DEF_HELPER_2(fctiw, i64, env, i64)
|
||||
DEF_HELPER_2(fctiwu, i64, env, i64)
|
||||
DEF_HELPER_2(fctiwz, i64, env, i64)
|
||||
DEF_HELPER_2(fctiwuz, i64, env, i64)
|
||||
DEF_HELPER_2(fcfid, i64, env, i64)
|
||||
DEF_HELPER_2(fcfidu, i64, env, i64)
|
||||
DEF_HELPER_2(fcfids, i64, env, i64)
|
||||
DEF_HELPER_2(fcfidus, i64, env, i64)
|
||||
DEF_HELPER_2(fctid, i64, env, i64)
|
||||
DEF_HELPER_2(fctidu, i64, env, i64)
|
||||
DEF_HELPER_2(fctidz, i64, env, i64)
|
||||
DEF_HELPER_2(fctiduz, i64, env, i64)
|
||||
DEF_HELPER_2(frsp, i64, env, i64)
|
||||
DEF_HELPER_2(frin, i64, env, i64)
|
||||
DEF_HELPER_2(friz, i64, env, i64)
|
||||
DEF_HELPER_2(frip, i64, env, i64)
|
||||
DEF_HELPER_2(frim, i64, env, i64)
|
||||
DEF_HELPER_2(FCTIW, i64, env, i64)
|
||||
DEF_HELPER_2(FCTIWU, i64, env, i64)
|
||||
DEF_HELPER_2(FCTIWZ, i64, env, i64)
|
||||
DEF_HELPER_2(FCTIWUZ, i64, env, i64)
|
||||
DEF_HELPER_2(FCFID, i64, env, i64)
|
||||
DEF_HELPER_2(FCFIDU, i64, env, i64)
|
||||
DEF_HELPER_2(FCFIDS, i64, env, i64)
|
||||
DEF_HELPER_2(FCFIDUS, i64, env, i64)
|
||||
DEF_HELPER_2(FCTID, i64, env, i64)
|
||||
DEF_HELPER_2(FCTIDU, i64, env, i64)
|
||||
DEF_HELPER_2(FCTIDZ, i64, env, i64)
|
||||
DEF_HELPER_2(FCTIDUZ, i64, env, i64)
|
||||
DEF_HELPER_2(FRSP, i64, env, i64)
|
||||
DEF_HELPER_2(FRIN, i64, env, i64)
|
||||
DEF_HELPER_2(FRIZ, i64, env, i64)
|
||||
DEF_HELPER_2(FRIP, i64, env, i64)
|
||||
DEF_HELPER_2(FRIM, i64, env, i64)
|
||||
|
||||
DEF_HELPER_3(FADD, f64, env, f64, f64)
|
||||
DEF_HELPER_3(FADDS, f64, env, f64, f64)
|
||||
|
||||
+29
-16
@@ -186,6 +186,10 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
|
||||
if (env->spr[SPR_LPCR] & LPCR_HR) {
|
||||
hflags |= 1 << HFLAGS_HR;
|
||||
}
|
||||
if (unlikely(ppc_flags & POWERPC_FLAG_PPE42)) {
|
||||
/* PPE42 has a single address space and no problem state */
|
||||
msr = 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
|
||||
@@ -308,9 +312,6 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv)
|
||||
value &= ~(1 << MSR_ME);
|
||||
value |= env->msr & (1 << MSR_ME);
|
||||
}
|
||||
if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) {
|
||||
cpu_interrupt_exittb(cs);
|
||||
}
|
||||
if ((env->mmu_model == POWERPC_MMU_BOOKE ||
|
||||
env->mmu_model == POWERPC_MMU_BOOKE206) &&
|
||||
((value ^ env->msr) & R_MSR_GS_MASK)) {
|
||||
@@ -321,8 +322,14 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv)
|
||||
/* Swap temporary saved registers with GPRs */
|
||||
hreg_swap_gpr_tgpr(env);
|
||||
}
|
||||
if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) {
|
||||
env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000;
|
||||
/* PPE42 uses IR, DR and EP MSR bits for other purposes */
|
||||
if (likely(!(env->flags & POWERPC_FLAG_PPE42))) {
|
||||
if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) {
|
||||
cpu_interrupt_exittb(cs);
|
||||
}
|
||||
if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) {
|
||||
env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If PR=1 then EE, IR and DR must be 1
|
||||
@@ -464,6 +471,23 @@ void register_generic_sprs(PowerPCCPU *cpu)
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
|
||||
spr_register(env, SPR_PVR, "PVR",
|
||||
/* Linux permits userspace to read PVR */
|
||||
#if defined(CONFIG_LINUX_USER)
|
||||
&spr_read_generic,
|
||||
#else
|
||||
SPR_NOACCESS,
|
||||
#endif
|
||||
SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
pcc->pvr);
|
||||
|
||||
/* PPE42 doesn't support SPRG1-3, SVR or TB regs */
|
||||
if (env->insns_flags2 & PPC2_PPE42) {
|
||||
return;
|
||||
}
|
||||
|
||||
spr_register(env, SPR_SPRG1, "SPRG1",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
@@ -477,17 +501,6 @@ void register_generic_sprs(PowerPCCPU *cpu)
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
|
||||
spr_register(env, SPR_PVR, "PVR",
|
||||
/* Linux permits userspace to read PVR */
|
||||
#if defined(CONFIG_LINUX_USER)
|
||||
&spr_read_generic,
|
||||
#else
|
||||
SPR_NOACCESS,
|
||||
#endif
|
||||
SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
pcc->pvr);
|
||||
|
||||
/* Register SVR if it's defined to anything else than POWERPC_SVR_NONE */
|
||||
if (pcc->svr != POWERPC_SVR_NONE) {
|
||||
if (pcc->svr & POWERPC_SVR_E500) {
|
||||
|
||||
+102
-4
@@ -58,6 +58,10 @@
|
||||
%ds_rtp 22:4 !function=times_2
|
||||
@DS_rtp ...... ....0 ra:5 .............. .. &D rt=%ds_rtp si=%ds_si
|
||||
|
||||
%dd_si 3:s13
|
||||
&DD rt ra si:int64_t
|
||||
@DD ...... rt:5 ra:5 ............. . .. &DD si=%dd_si
|
||||
|
||||
&DX_b vrt b
|
||||
%dx_b 6:10 16:5 0:1
|
||||
@DX_b ...... vrt:5 ..... .......... ..... . &DX_b b=%dx_b
|
||||
@@ -66,6 +70,11 @@
|
||||
%dx_d 6:s10 16:5 0:1
|
||||
@DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d
|
||||
|
||||
%md_sh 1:1 11:5
|
||||
%md_mb 5:1 6:5
|
||||
&MD rs ra sh mb rc
|
||||
@MD ...... rs:5 ra:5 ..... ...... ... . rc:1 &MD sh=%md_sh mb=%md_mb
|
||||
|
||||
&VA vrt vra vrb rc
|
||||
@VA ...... vrt:5 vra:5 vrb:5 rc:5 ...... &VA
|
||||
|
||||
@@ -322,6 +331,13 @@ LDUX 011111 ..... ..... ..... 0000110101 - @X
|
||||
|
||||
LQ 111000 ..... ..... ............ ---- @DQ_rtp
|
||||
|
||||
LVD 000101 ..... ..... ................ @D
|
||||
LVDU 001001 ..... ..... ................ @D
|
||||
LVDX 011111 ..... ..... ..... 0000010001 - @X
|
||||
LSKU 111010 ..... ..... ............. 0 11 @DD
|
||||
LCXU 111010 ..... ..... ............. 1 11 @DD
|
||||
|
||||
|
||||
### Fixed-Point Store Instructions
|
||||
|
||||
STB 100110 ..... ..... ................ @D
|
||||
@@ -346,6 +362,11 @@ STDUX 011111 ..... ..... ..... 0010110101 - @X
|
||||
|
||||
STQ 111110 ..... ..... ..............10 @DS_rtp
|
||||
|
||||
STVDU 010110 ..... ..... ................ @D
|
||||
STVDX 011111 ..... ..... ..... 0010010001 - @X
|
||||
STSKU 111110 ..... ..... ............. 0 11 @DD
|
||||
STCXU 111110 ..... ..... ............. 1 11 @DD
|
||||
|
||||
### Fixed-Point Compare Instructions
|
||||
|
||||
CMP 011111 ... - . ..... ..... 0000000000 - @X_bfl
|
||||
@@ -461,8 +482,14 @@ PRTYD 011111 ..... ..... ----- 0010111010 - @X_sa
|
||||
|
||||
BPERMD 011111 ..... ..... ..... 0011111100 - @X
|
||||
CFUGED 011111 ..... ..... ..... 0011011100 - @X
|
||||
CNTLZDM 011111 ..... ..... ..... 0000111011 - @X
|
||||
CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
|
||||
{
|
||||
SLVD 011111 ..... ..... ..... 0000111011 . @X_rc
|
||||
CNTLZDM 011111 ..... ..... ..... 0000111011 - @X
|
||||
}
|
||||
{
|
||||
SRVD 011111 ..... ..... ..... 1000111011 . @X_rc
|
||||
CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
|
||||
}
|
||||
PDEPD 011111 ..... ..... ..... 0010011100 - @X
|
||||
PEXTD 011111 ..... ..... ..... 0010111100 - @X
|
||||
|
||||
@@ -503,6 +530,17 @@ STFDU 110111 ..... ...... ............... @D
|
||||
STFDX 011111 ..... ...... .... 1011010111 - @X
|
||||
STFDUX 011111 ..... ...... .... 1011110111 - @X
|
||||
|
||||
### Floating-Point Move Instructions
|
||||
|
||||
FMR 111111 ..... ----- ..... 0001001000 . @X_tb_rc
|
||||
FNEG 111111 ..... ----- ..... 0000101000 . @X_tb_rc
|
||||
FABS 111111 ..... ----- ..... 0100001000 . @X_tb_rc
|
||||
FNABS 111111 ..... ----- ..... 0010001000 . @X_tb_rc
|
||||
|
||||
FCPSGN 111111 ..... ..... ..... 0000001000 . @X_rc
|
||||
FMRGEW 111111 ..... ..... ..... 1111000110 - @X
|
||||
FMRGOW 111111 ..... ..... ..... 1101000110 - @X
|
||||
|
||||
### Floating-Point Arithmetic Instructions
|
||||
|
||||
FADD 111111 ..... ..... ..... ----- 10101 . @A_tab
|
||||
@@ -541,6 +579,35 @@ FNMADDS 111011 ..... ..... ..... ..... 11111 . @A
|
||||
FNMSUB 111111 ..... ..... ..... ..... 11110 . @A
|
||||
FNMSUBS 111011 ..... ..... ..... ..... 11110 . @A
|
||||
|
||||
### Floating-Point Rounding and Conversion Instructions
|
||||
|
||||
FRSP 111111 ..... ----- ..... 0000001100 . @X_tb_rc
|
||||
|
||||
FRIN 111111 ..... ----- ..... 0110001000 . @X_tb_rc
|
||||
FRIZ 111111 ..... ----- ..... 0110101000 . @X_tb_rc
|
||||
FRIP 111111 ..... ----- ..... 0111001000 . @X_tb_rc
|
||||
FRIM 111111 ..... ----- ..... 0111101000 . @X_tb_rc
|
||||
|
||||
FCTIW 111111 ..... ----- ..... 0000001110 . @X_tb_rc
|
||||
FCTIWU 111111 ..... ----- ..... 0010001110 . @X_tb_rc
|
||||
FCTIWZ 111111 ..... ----- ..... 0000001111 . @X_tb_rc
|
||||
FCTIWUZ 111111 ..... ----- ..... 0010001111 . @X_tb_rc
|
||||
|
||||
FCTID 111111 ..... ----- ..... 1100101110 . @X_tb_rc
|
||||
FCTIDU 111111 ..... ----- ..... 1110101110 . @X_tb_rc
|
||||
FCTIDZ 111111 ..... ----- ..... 1100101111 . @X_tb_rc
|
||||
FCTIDUZ 111111 ..... ----- ..... 1110101111 . @X_tb_rc
|
||||
|
||||
FCFID 111111 ..... ----- ..... 1101001110 . @X_tb_rc
|
||||
FCFIDS 111011 ..... ----- ..... 1101001110 . @X_tb_rc
|
||||
FCFIDU 111111 ..... ----- ..... 1111001110 . @X_tb_rc
|
||||
FCFIDUS 111011 ..... ----- ..... 1111001110 . @X_tb_rc
|
||||
|
||||
### Floating-Point Compare Instructions
|
||||
|
||||
FCMPU 111111 ... -- ..... ..... 0000000000 - @X_bf
|
||||
FCMPO 111111 ... -- ..... ..... 0000100000 - @X_bf
|
||||
|
||||
### Floating-Point Select Instruction
|
||||
|
||||
FSEL 111111 ..... ..... ..... ..... 10111 . @A
|
||||
@@ -981,8 +1048,16 @@ LXSSP 111001 ..... ..... .............. 11 @DS
|
||||
STXSSP 111101 ..... ..... .............. 11 @DS
|
||||
LXV 111101 ..... ..... ............ . 001 @DQ_TSX
|
||||
STXV 111101 ..... ..... ............ . 101 @DQ_TSX
|
||||
LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP
|
||||
STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP
|
||||
|
||||
# STVD PPE instruction overlaps with the LXVP and STXVP instructions
|
||||
{
|
||||
STVD 000110 ..... ..... ................ @D
|
||||
[
|
||||
LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP
|
||||
STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP
|
||||
]
|
||||
}
|
||||
|
||||
LXVX 011111 ..... ..... ..... 0100 - 01100 . @X_TSX
|
||||
STXVX 011111 ..... ..... ..... 0110001100 . @X_TSX
|
||||
LXVPX 011111 ..... ..... ..... 0101001101 - @X_TSXP
|
||||
@@ -1300,3 +1375,26 @@ CLRBHRB 011111 ----- ----- ----- 0110101110 -
|
||||
## Misc POWER instructions
|
||||
|
||||
ATTN 000000 00000 00000 00000 0100000000 0
|
||||
|
||||
# Fused compare-branch instructions for PPE only
|
||||
%fcb_bdx 1:s10 !function=times_4
|
||||
&FCB px:bool ra rb:uint64_t bdx lk:bool
|
||||
@FCB ...... .. px:1 .. ra:5 rb:5 .......... lk:1 &FCB bdx=%fcb_bdx
|
||||
&FCB_bix px:bool bix ra rb:uint64_t bdx lk:bool
|
||||
@FCB_bix ...... .. px:1 bix:2 ra:5 rb:5 .......... lk:1 &FCB_bix bdx=%fcb_bdx
|
||||
|
||||
CMPWBC 000001 00 . .. ..... ..... .......... . @FCB_bix
|
||||
CMPLWBC 000001 01 . .. ..... ..... .......... . @FCB_bix
|
||||
CMPWIBC 000001 10 . .. ..... ..... .......... . @FCB_bix
|
||||
BNBWI 000001 11 . 00 ..... ..... .......... . @FCB
|
||||
BNBW 000001 11 . 01 ..... ..... .......... . @FCB
|
||||
CLRBWIBC 000001 11 . 10 ..... ..... .......... . @FCB
|
||||
CLRBWBC 000001 11 . 11 ..... ..... .......... . @FCB
|
||||
|
||||
# Data Cache Block Query for PPE only
|
||||
DCBQ 011111 ..... ..... ..... 0110010110 - @X
|
||||
|
||||
# Rotate Doubleword Instructions for PPE only
|
||||
RLDICL 011110 ..... ..... ..... ...... 000 . . @MD
|
||||
RLDICR 011110 ..... ..... ..... ...... 001 . . @MD
|
||||
RLDIMI 011110 ..... ..... ..... ...... 011 . . @MD
|
||||
|
||||
@@ -229,6 +229,18 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
|
||||
case POWERPC_MMU_BOOKE206:
|
||||
env->spr[SPR_BOOKE_DEAR] = vaddr;
|
||||
break;
|
||||
case POWERPC_MMU_REAL:
|
||||
if (env->flags & POWERPC_FLAG_PPE42) {
|
||||
env->spr[SPR_PPE42_EDR] = vaddr;
|
||||
if (access_type == MMU_DATA_STORE) {
|
||||
env->spr[SPR_PPE42_ISR] |= PPE42_ISR_ST;
|
||||
} else {
|
||||
env->spr[SPR_PPE42_ISR] &= ~PPE42_ISR_ST;
|
||||
}
|
||||
} else {
|
||||
env->spr[SPR_DAR] = vaddr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
env->spr[SPR_DAR] = vaddr;
|
||||
break;
|
||||
|
||||
+27
-8
@@ -209,6 +209,11 @@ struct DisasContext {
|
||||
#define DISAS_CHAIN DISAS_TARGET_2 /* lookup next tb, pc updated */
|
||||
#define DISAS_CHAIN_UPDATE DISAS_TARGET_3 /* lookup next tb, pc stale */
|
||||
|
||||
static inline bool is_ppe(const DisasContext *ctx)
|
||||
{
|
||||
return !!(ctx->flags & POWERPC_FLAG_PPE42);
|
||||
}
|
||||
|
||||
/* Return true iff byteswap is needed in a scalar memop */
|
||||
static inline bool need_byteswap(const DisasContext *ctx)
|
||||
{
|
||||
@@ -556,11 +561,8 @@ void spr_access_nop(DisasContext *ctx, int sprn, int gprn)
|
||||
|
||||
#endif
|
||||
|
||||
/* SPR common to all PowerPC */
|
||||
/* XER */
|
||||
void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
|
||||
static void gen_get_xer(DisasContext *ctx, TCGv dst)
|
||||
{
|
||||
TCGv dst = cpu_gpr[gprn];
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
TCGv t2 = tcg_temp_new();
|
||||
@@ -579,9 +581,16 @@ void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
|
||||
}
|
||||
}
|
||||
|
||||
void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
|
||||
/* SPR common to all PowerPC */
|
||||
/* XER */
|
||||
void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
TCGv dst = cpu_gpr[gprn];
|
||||
gen_get_xer(ctx, dst);
|
||||
}
|
||||
|
||||
static void gen_set_xer(DisasContext *ctx, TCGv src)
|
||||
{
|
||||
TCGv src = cpu_gpr[gprn];
|
||||
/* Write all flags, while reading back check for isa300 */
|
||||
tcg_gen_andi_tl(cpu_xer, src,
|
||||
~((1u << XER_SO) |
|
||||
@@ -594,6 +603,12 @@ void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
|
||||
tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1);
|
||||
}
|
||||
|
||||
void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
TCGv src = cpu_gpr[gprn];
|
||||
gen_set_xer(ctx, src);
|
||||
}
|
||||
|
||||
/* LR */
|
||||
void spr_read_lr(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
@@ -4264,8 +4279,10 @@ static void gen_mtmsr(DisasContext *ctx)
|
||||
/* L=1 form only updates EE and RI */
|
||||
mask &= (1ULL << MSR_RI) | (1ULL << MSR_EE);
|
||||
} else {
|
||||
/* mtmsr does not alter S, ME, or LE */
|
||||
mask &= ~((1ULL << MSR_LE) | (1ULL << MSR_ME) | (1ULL << MSR_S));
|
||||
if (likely(!(ctx->insns_flags2 & PPC2_PPE42))) {
|
||||
/* mtmsr does not alter S, ME, or LE */
|
||||
mask &= ~((1ULL << MSR_LE) | (1ULL << MSR_ME) | (1ULL << MSR_S));
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: we need to update nip before the store if we enter
|
||||
@@ -5753,6 +5770,8 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a)
|
||||
|
||||
#include "translate/bhrb-impl.c.inc"
|
||||
|
||||
#include "translate/ppe-impl.c.inc"
|
||||
|
||||
/* Handles lfdp */
|
||||
static void gen_dform39(DisasContext *ctx)
|
||||
{
|
||||
|
||||
+107
-192
@@ -98,28 +98,26 @@ static bool do_helper_ac(DisasContext *ctx, arg_A_tac *a,
|
||||
return true;
|
||||
}
|
||||
|
||||
#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \
|
||||
static void gen_f##name(DisasContext *ctx) \
|
||||
{ \
|
||||
TCGv_i64 t0; \
|
||||
TCGv_i64 t1; \
|
||||
if (unlikely(!ctx->fpu_enabled)) { \
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU); \
|
||||
return; \
|
||||
} \
|
||||
t0 = tcg_temp_new_i64(); \
|
||||
t1 = tcg_temp_new_i64(); \
|
||||
gen_reset_fpstatus(); \
|
||||
get_fpr(t0, rB(ctx->opcode)); \
|
||||
gen_helper_f##name(t1, tcg_env, t0); \
|
||||
set_fpr(rD(ctx->opcode), t1); \
|
||||
if (set_fprf) { \
|
||||
gen_helper_compute_fprf_float64(tcg_env, t1); \
|
||||
} \
|
||||
gen_helper_float_check_status(tcg_env); \
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) { \
|
||||
gen_set_cr1_from_fpscr(ctx); \
|
||||
} \
|
||||
static bool do_round_convert(DisasContext *ctx, arg_X_tb_rc *a,
|
||||
void (*helper)(TCGv_i64, TCGv_env, TCGv_i64),
|
||||
bool set_fprf)
|
||||
{
|
||||
TCGv_i64 t0, t1;
|
||||
REQUIRE_FPU(ctx);
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
gen_reset_fpstatus();
|
||||
get_fpr(t0, a->rb);
|
||||
helper(t1, tcg_env, t0);
|
||||
set_fpr(a->rt, t1);
|
||||
if (set_fprf) {
|
||||
gen_helper_compute_fprf_float64(tcg_env, t1);
|
||||
}
|
||||
gen_helper_float_check_status(tcg_env);
|
||||
if (unlikely(a->rc)) {
|
||||
gen_set_cr1_from_fpscr(ctx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_helper_bs(DisasContext *ctx, arg_A_tb *a,
|
||||
@@ -213,41 +211,26 @@ TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT);
|
||||
TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS);
|
||||
|
||||
/*** Floating-Point round & convert ***/
|
||||
/* fctiw */
|
||||
GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
|
||||
/* fctiwu */
|
||||
GEN_FLOAT_B(ctiwu, 0x0E, 0x04, 0, PPC2_FP_CVT_ISA206);
|
||||
/* fctiwz */
|
||||
GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
|
||||
/* fctiwuz */
|
||||
GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206);
|
||||
/* frsp */
|
||||
GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
|
||||
/* fcfid */
|
||||
GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64);
|
||||
/* fcfids */
|
||||
GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206);
|
||||
/* fcfidu */
|
||||
GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
|
||||
/* fcfidus */
|
||||
GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
|
||||
/* fctid */
|
||||
GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64);
|
||||
/* fctidu */
|
||||
GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206);
|
||||
/* fctidz */
|
||||
GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64);
|
||||
/* fctidu */
|
||||
GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206);
|
||||
TRANS_FLAGS(FLOAT, FRSP, do_round_convert, gen_helper_FRSP, true);
|
||||
TRANS_FLAGS(FLOAT_EXT, FRIN, do_round_convert, gen_helper_FRIN, true);
|
||||
TRANS_FLAGS(FLOAT_EXT, FRIZ, do_round_convert, gen_helper_FRIZ, true);
|
||||
TRANS_FLAGS(FLOAT_EXT, FRIP, do_round_convert, gen_helper_FRIP, true);
|
||||
TRANS_FLAGS(FLOAT_EXT, FRIM, do_round_convert, gen_helper_FRIM, true);
|
||||
|
||||
/* frin */
|
||||
GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
|
||||
/* friz */
|
||||
GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
|
||||
/* frip */
|
||||
GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
|
||||
/* frim */
|
||||
GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
|
||||
TRANS_FLAGS(FLOAT, FCTIW, do_round_convert, gen_helper_FCTIW, false);
|
||||
TRANS_FLAGS2(FP_CVT_ISA206, FCTIWU, do_round_convert, gen_helper_FCTIWU, false);
|
||||
TRANS_FLAGS(FLOAT, FCTIWZ, do_round_convert, gen_helper_FCTIWZ, false);
|
||||
TRANS_FLAGS2(FP_CVT_ISA206, FCTIWUZ, do_round_convert, gen_helper_FCTIWUZ, false);
|
||||
|
||||
TRANS_FLAGS2(FP_CVT_S64, FCTID, do_round_convert, gen_helper_FCTID, false);
|
||||
TRANS_FLAGS2(FP_CVT_ISA206, FCTIDU, do_round_convert, gen_helper_FCTIDU, false);
|
||||
TRANS_FLAGS2(FP_CVT_S64, FCTIDZ, do_round_convert, gen_helper_FCTIDZ, false);
|
||||
TRANS_FLAGS2(FP_CVT_ISA206, FCTIDUZ, do_round_convert, gen_helper_FCTIDUZ, false);
|
||||
|
||||
TRANS_FLAGS2(FP_CVT_S64, FCFID, do_round_convert, gen_helper_FCFID, true);
|
||||
TRANS_FLAGS2(FP_CVT_ISA206, FCFIDS, do_round_convert, gen_helper_FCFIDS, false);
|
||||
TRANS_FLAGS2(FP_CVT_ISA206, FCFIDU, do_round_convert, gen_helper_FCFIDU, false);
|
||||
TRANS_FLAGS2(FP_CVT_ISA206, FCFIDUS, do_round_convert, gen_helper_FCFIDUS, false);
|
||||
|
||||
static bool trans_FTDIV(DisasContext *ctx, arg_X_bf *a)
|
||||
{
|
||||
@@ -274,183 +257,117 @@ static bool trans_FTSQRT(DisasContext *ctx, arg_X_bf_b *a)
|
||||
}
|
||||
|
||||
/*** Floating-Point compare ***/
|
||||
|
||||
/* fcmpo */
|
||||
static void gen_fcmpo(DisasContext *ctx)
|
||||
static bool do_helper_cmp(DisasContext *ctx, arg_X_bf *a,
|
||||
void (*helper)(TCGv_env, TCGv_i64, TCGv_i64,
|
||||
TCGv_i32))
|
||||
{
|
||||
TCGv_i32 crf;
|
||||
TCGv_i64 t0;
|
||||
TCGv_i64 t1;
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
}
|
||||
TCGv_i64 t0, t1;
|
||||
REQUIRE_INSNS_FLAGS(ctx, FLOAT);
|
||||
REQUIRE_FPU(ctx);
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
gen_reset_fpstatus();
|
||||
crf = tcg_constant_i32(crfD(ctx->opcode));
|
||||
get_fpr(t0, rA(ctx->opcode));
|
||||
get_fpr(t1, rB(ctx->opcode));
|
||||
gen_helper_fcmpo(tcg_env, t0, t1, crf);
|
||||
crf = tcg_constant_i32(a->bf);
|
||||
get_fpr(t0, a->ra);
|
||||
get_fpr(t1, a->rb);
|
||||
helper(tcg_env, t0, t1, crf);
|
||||
gen_helper_float_check_status(tcg_env);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* fcmpu */
|
||||
static void gen_fcmpu(DisasContext *ctx)
|
||||
{
|
||||
TCGv_i32 crf;
|
||||
TCGv_i64 t0;
|
||||
TCGv_i64 t1;
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
}
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
gen_reset_fpstatus();
|
||||
crf = tcg_constant_i32(crfD(ctx->opcode));
|
||||
get_fpr(t0, rA(ctx->opcode));
|
||||
get_fpr(t1, rB(ctx->opcode));
|
||||
gen_helper_fcmpu(tcg_env, t0, t1, crf);
|
||||
gen_helper_float_check_status(tcg_env);
|
||||
}
|
||||
TRANS(FCMPU, do_helper_cmp, gen_helper_FCMPU);
|
||||
TRANS(FCMPO, do_helper_cmp, gen_helper_FCMPO);
|
||||
|
||||
/*** Floating-point move ***/
|
||||
/* fabs */
|
||||
/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
|
||||
static void gen_fabs(DisasContext *ctx)
|
||||
{
|
||||
TCGv_i64 t0;
|
||||
TCGv_i64 t1;
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
}
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
get_fpr(t0, rB(ctx->opcode));
|
||||
tcg_gen_andi_i64(t1, t0, ~(1ULL << 63));
|
||||
set_fpr(rD(ctx->opcode), t1);
|
||||
if (unlikely(Rc(ctx->opcode))) {
|
||||
gen_set_cr1_from_fpscr(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/* fmr - fmr. */
|
||||
/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
|
||||
static void gen_fmr(DisasContext *ctx)
|
||||
static bool trans_FMR(DisasContext *ctx, arg_FMR *a)
|
||||
{
|
||||
TCGv_i64 t0;
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
}
|
||||
REQUIRE_INSNS_FLAGS(ctx, FLOAT);
|
||||
REQUIRE_FPU(ctx);
|
||||
t0 = tcg_temp_new_i64();
|
||||
get_fpr(t0, rB(ctx->opcode));
|
||||
set_fpr(rD(ctx->opcode), t0);
|
||||
if (unlikely(Rc(ctx->opcode))) {
|
||||
get_fpr(t0, a->rb);
|
||||
set_fpr(a->rt, t0);
|
||||
if (unlikely(a->rc)) {
|
||||
gen_set_cr1_from_fpscr(ctx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* fnabs */
|
||||
/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
|
||||
static void gen_fnabs(DisasContext *ctx)
|
||||
/* XXX: beware that f{neg, abs, nabs} never checks for NaNs nor update FPSCR */
|
||||
static bool do_move_b(DisasContext *ctx, arg_X_tb_rc *a, int64_t val,
|
||||
void (*tcg_op)(TCGv_i64, TCGv_i64, int64_t))
|
||||
{
|
||||
TCGv_i64 t0;
|
||||
TCGv_i64 t1;
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
}
|
||||
TCGv_i64 t0, t1;
|
||||
REQUIRE_INSNS_FLAGS(ctx, FLOAT);
|
||||
REQUIRE_FPU(ctx);
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
get_fpr(t0, rB(ctx->opcode));
|
||||
tcg_gen_ori_i64(t1, t0, 1ULL << 63);
|
||||
set_fpr(rD(ctx->opcode), t1);
|
||||
if (unlikely(Rc(ctx->opcode))) {
|
||||
get_fpr(t0, a->rb);
|
||||
tcg_op(t1, t0, val);
|
||||
set_fpr(a->rt, t1);
|
||||
if (unlikely(a->rc)) {
|
||||
gen_set_cr1_from_fpscr(ctx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* fneg */
|
||||
/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
|
||||
static void gen_fneg(DisasContext *ctx)
|
||||
{
|
||||
TCGv_i64 t0;
|
||||
TCGv_i64 t1;
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
}
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
get_fpr(t0, rB(ctx->opcode));
|
||||
tcg_gen_xori_i64(t1, t0, 1ULL << 63);
|
||||
set_fpr(rD(ctx->opcode), t1);
|
||||
if (unlikely(Rc(ctx->opcode))) {
|
||||
gen_set_cr1_from_fpscr(ctx);
|
||||
}
|
||||
}
|
||||
TRANS(FNEG, do_move_b, 1ULL << 63, tcg_gen_xori_i64);
|
||||
TRANS(FABS, do_move_b, ~(1ULL << 63), tcg_gen_andi_i64);
|
||||
TRANS(FNABS, do_move_b, 1ULL << 63, tcg_gen_ori_i64);
|
||||
|
||||
/* fcpsgn: PowerPC 2.05 specification */
|
||||
/* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */
|
||||
static void gen_fcpsgn(DisasContext *ctx)
|
||||
static bool trans_FCPSGN(DisasContext *ctx, arg_FCPSGN *a)
|
||||
{
|
||||
TCGv_i64 t0;
|
||||
TCGv_i64 t1;
|
||||
TCGv_i64 t2;
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
}
|
||||
TCGv_i64 t0, t1, t2;
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA205);
|
||||
REQUIRE_FPU(ctx);
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
t2 = tcg_temp_new_i64();
|
||||
get_fpr(t0, rA(ctx->opcode));
|
||||
get_fpr(t1, rB(ctx->opcode));
|
||||
get_fpr(t0, a->ra);
|
||||
get_fpr(t1, a->rb);
|
||||
tcg_gen_deposit_i64(t2, t0, t1, 0, 63);
|
||||
set_fpr(rD(ctx->opcode), t2);
|
||||
if (unlikely(Rc(ctx->opcode))) {
|
||||
set_fpr(a->rt, t2);
|
||||
if (unlikely(a->rc)) {
|
||||
gen_set_cr1_from_fpscr(ctx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void gen_fmrgew(DisasContext *ctx)
|
||||
static bool trans_FMRGEW(DisasContext *ctx, arg_FMRGEW *a)
|
||||
{
|
||||
TCGv_i64 b0;
|
||||
TCGv_i64 t0;
|
||||
TCGv_i64 t1;
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
}
|
||||
b0 = tcg_temp_new_i64();
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
get_fpr(t0, rB(ctx->opcode));
|
||||
tcg_gen_shri_i64(b0, t0, 32);
|
||||
get_fpr(t0, rA(ctx->opcode));
|
||||
tcg_gen_deposit_i64(t1, t0, b0, 0, 32);
|
||||
set_fpr(rD(ctx->opcode), t1);
|
||||
}
|
||||
|
||||
static void gen_fmrgow(DisasContext *ctx)
|
||||
{
|
||||
TCGv_i64 t0;
|
||||
TCGv_i64 t1;
|
||||
TCGv_i64 t2;
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
}
|
||||
TCGv_i64 t0, t1, t2;
|
||||
REQUIRE_INSNS_FLAGS2(ctx, VSX207);
|
||||
REQUIRE_FPU(ctx);
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
t2 = tcg_temp_new_i64();
|
||||
get_fpr(t0, rB(ctx->opcode));
|
||||
get_fpr(t1, rA(ctx->opcode));
|
||||
get_fpr(t1, a->rb);
|
||||
tcg_gen_shri_i64(t0, t1, 32);
|
||||
get_fpr(t1, a->ra);
|
||||
tcg_gen_deposit_i64(t2, t1, t0, 0, 32);
|
||||
set_fpr(a->rt, t2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_FMRGOW(DisasContext *ctx, arg_FMRGOW *a)
|
||||
{
|
||||
TCGv_i64 t0, t1, t2;
|
||||
REQUIRE_INSNS_FLAGS2(ctx, VSX207);
|
||||
REQUIRE_FPU(ctx);
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
t2 = tcg_temp_new_i64();
|
||||
get_fpr(t0, a->rb);
|
||||
get_fpr(t1, a->ra);
|
||||
tcg_gen_deposit_i64(t2, t0, t1, 32, 32);
|
||||
set_fpr(rD(ctx->opcode), t2);
|
||||
set_fpr(a->rt, t2);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*** Floating-Point status & ctrl register ***/
|
||||
@@ -479,7 +396,7 @@ static void gen_mcrfs(DisasContext *ctx)
|
||||
tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr);
|
||||
/* Only the exception bits (including FX) should be cleared if read */
|
||||
tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr,
|
||||
~((0xF << shift) & FP_EX_CLEAR_BITS));
|
||||
~(MAKE_64BIT_MASK(shift, 4) & FP_EX_CLEAR_BITS));
|
||||
/* FEX and VX need to be updated, so don't set fpscr directly */
|
||||
tmask = tcg_constant_i32(1 << nibble);
|
||||
gen_helper_store_fpscr(tcg_env, tnew_fpscr, tmask);
|
||||
@@ -1051,8 +968,6 @@ TRANS(STFDX, do_lsfp_X, false, true, false)
|
||||
TRANS(STFDUX, do_lsfp_X, true, true, false)
|
||||
TRANS(PSTFD, do_lsfp_PLS_D, false, true, false)
|
||||
|
||||
#undef GEN_FLOAT_B
|
||||
|
||||
#undef GEN_LDF
|
||||
#undef GEN_LDUF
|
||||
#undef GEN_LDUXF
|
||||
|
||||
@@ -1,24 +1,3 @@
|
||||
#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \
|
||||
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type)
|
||||
|
||||
GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT),
|
||||
GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||
GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT),
|
||||
GEN_HANDLER_E(fctiwuz, 0x3F, 0x0F, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||
GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT),
|
||||
GEN_HANDLER_E(fcfid, 0x3F, 0x0E, 0x1A, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
|
||||
GEN_HANDLER_E(fcfids, 0x3B, 0x0E, 0x1A, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||
GEN_HANDLER_E(fcfidu, 0x3F, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||
GEN_HANDLER_E(fcfidus, 0x3B, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||
GEN_HANDLER_E(fctid, 0x3F, 0x0E, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
|
||||
GEN_HANDLER_E(fctidu, 0x3F, 0x0E, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||
GEN_HANDLER_E(fctidz, 0x3F, 0x0F, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
|
||||
GEN_HANDLER_E(fctiduz, 0x3F, 0x0F, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||
GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT),
|
||||
GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT),
|
||||
GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT),
|
||||
GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT),
|
||||
|
||||
GEN_HANDLER_E(lfdepx, 0x1F, 0x1F, 0x12, 0x00000001, PPC_NONE, PPC2_BOOKE206),
|
||||
GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205),
|
||||
GEN_HANDLER_E(lfiwzx, 0x1f, 0x17, 0x1b, 0x1, PPC_NONE, PPC2_FP_CVT_ISA206),
|
||||
@@ -31,15 +10,6 @@ GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX)
|
||||
GEN_HANDLER_E(stfdepx, 0x1F, 0x1F, 0x16, 0x00000001, PPC_NONE, PPC2_BOOKE206),
|
||||
GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205),
|
||||
|
||||
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT),
|
||||
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT),
|
||||
GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT),
|
||||
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT),
|
||||
GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT),
|
||||
GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT),
|
||||
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(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT),
|
||||
GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT),
|
||||
|
||||
@@ -0,0 +1,609 @@
|
||||
/*
|
||||
* IBM PPE Instructions
|
||||
*
|
||||
* Copyright (c) 2025, IBM Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
|
||||
static bool vdr_is_valid(uint32_t vdr)
|
||||
{
|
||||
const uint32_t valid_bitmap = 0xf00003ff;
|
||||
return !!((1ul << (vdr & 0x1f)) & valid_bitmap);
|
||||
}
|
||||
|
||||
static bool ppe_gpr_is_valid(uint32_t reg)
|
||||
{
|
||||
const uint32_t valid_bitmap = 0xf00027ff;
|
||||
return !!((1ul << (reg & 0x1f)) & valid_bitmap);
|
||||
}
|
||||
|
||||
#define CHECK_VDR(CTX, VDR) \
|
||||
do { \
|
||||
if (unlikely(!vdr_is_valid(VDR))) { \
|
||||
gen_invalid(CTX); \
|
||||
return true; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_PPE_GPR(CTX, REG) \
|
||||
do { \
|
||||
if (unlikely(!ppe_gpr_is_valid(REG))) { \
|
||||
gen_invalid(CTX); \
|
||||
return true; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VDR_PAIR_REG(VDR) (((VDR) + 1) & 0x1f)
|
||||
|
||||
#define CHECK_PPE_LEVEL(CTX, LVL) \
|
||||
do { \
|
||||
if (unlikely(!((CTX)->insns_flags2 & (LVL)))) { \
|
||||
gen_invalid(CTX); \
|
||||
return true; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static bool trans_LCXU(DisasContext *ctx, arg_LCXU *a)
|
||||
{
|
||||
int i;
|
||||
TCGv base, EA;
|
||||
TCGv lo, hi;
|
||||
TCGv_i64 t8;
|
||||
const uint8_t vd_list[] = {9, 7, 5, 3, 0};
|
||||
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
|
||||
CHECK_PPE_GPR(ctx, a->rt);
|
||||
|
||||
if (unlikely((a->rt != a->ra) || (a->ra == 0) || (a->si < 0xB))) {
|
||||
gen_invalid(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
EA = tcg_temp_new();
|
||||
base = tcg_temp_new();
|
||||
|
||||
tcg_gen_addi_tl(base, cpu_gpr[a->ra], a->si * 8);
|
||||
gen_store_spr(SPR_PPE42_EDR, base);
|
||||
|
||||
t8 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_addi_tl(EA, base, -8);
|
||||
tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
tcg_gen_extr_i64_tl(cpu_gpr[31], cpu_gpr[30], t8);
|
||||
|
||||
tcg_gen_addi_tl(EA, EA, -8);
|
||||
tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
tcg_gen_extr_i64_tl(cpu_gpr[29], cpu_gpr[28], t8);
|
||||
|
||||
lo = tcg_temp_new();
|
||||
hi = tcg_temp_new();
|
||||
|
||||
tcg_gen_addi_tl(EA, EA, -8);
|
||||
tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
tcg_gen_extr_i64_tl(lo, hi, t8);
|
||||
gen_store_spr(SPR_SRR0, hi);
|
||||
gen_store_spr(SPR_SRR1, lo);
|
||||
|
||||
tcg_gen_addi_tl(EA, EA, -8);
|
||||
tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
tcg_gen_extr_i64_tl(lo, hi, t8);
|
||||
gen_set_xer(ctx, hi);
|
||||
tcg_gen_mov_tl(cpu_ctr, lo);
|
||||
|
||||
for (i = 0; i < sizeof(vd_list); i++) {
|
||||
int vd = vd_list[i];
|
||||
tcg_gen_addi_tl(EA, EA, -8);
|
||||
tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
tcg_gen_extr_i64_tl(cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd], t8);
|
||||
}
|
||||
|
||||
tcg_gen_addi_tl(EA, EA, -8);
|
||||
tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
tcg_gen_extr_i64_tl(lo, hi, t8);
|
||||
tcg_gen_shri_tl(hi, hi, 28);
|
||||
tcg_gen_trunc_tl_i32(cpu_crf[0], hi);
|
||||
gen_store_spr(SPR_SPRG0, lo);
|
||||
|
||||
tcg_gen_addi_tl(EA, base, 4);
|
||||
tcg_gen_qemu_ld_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
|
||||
tcg_gen_mov_tl(cpu_gpr[a->ra], base);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_LSKU(DisasContext *ctx, arg_LSKU *a)
|
||||
{
|
||||
int64_t n;
|
||||
TCGv base, EA;
|
||||
TCGv lo, hi;
|
||||
TCGv_i64 t8;
|
||||
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
|
||||
CHECK_PPE_GPR(ctx, a->rt);
|
||||
|
||||
if (unlikely((a->rt != a->ra) || (a->ra == 0) ||
|
||||
(a->si & PPC_BIT(0)) || (a->si == 0))) {
|
||||
gen_invalid(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
EA = tcg_temp_new();
|
||||
base = tcg_temp_new();
|
||||
gen_addr_register(ctx, base);
|
||||
|
||||
|
||||
tcg_gen_addi_tl(base, base, a->si * 8);
|
||||
gen_store_spr(SPR_PPE42_EDR, base);
|
||||
|
||||
n = a->si - 1;
|
||||
t8 = tcg_temp_new_i64();
|
||||
if (n > 0) {
|
||||
tcg_gen_addi_tl(EA, base, -8);
|
||||
tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
hi = cpu_gpr[30];
|
||||
lo = cpu_gpr[31];
|
||||
tcg_gen_extr_i64_tl(lo, hi, t8);
|
||||
}
|
||||
if (n > 1) {
|
||||
tcg_gen_addi_tl(EA, base, -16);
|
||||
tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
hi = cpu_gpr[28];
|
||||
lo = cpu_gpr[29];
|
||||
tcg_gen_extr_i64_tl(lo, hi, t8);
|
||||
}
|
||||
tcg_gen_addi_tl(EA, base, 4);
|
||||
tcg_gen_qemu_ld_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
|
||||
tcg_gen_mov_tl(cpu_gpr[a->ra], base);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_STCXU(DisasContext *ctx, arg_STCXU *a)
|
||||
{
|
||||
TCGv EA;
|
||||
TCGv lo, hi;
|
||||
TCGv_i64 t8;
|
||||
int i;
|
||||
const uint8_t vd_list[] = {9, 7, 5, 3, 0};
|
||||
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
|
||||
CHECK_PPE_GPR(ctx, a->rt);
|
||||
|
||||
if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) {
|
||||
gen_invalid(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
EA = tcg_temp_new();
|
||||
tcg_gen_addi_tl(EA, cpu_gpr[a->ra], 4);
|
||||
tcg_gen_qemu_st_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
|
||||
|
||||
gen_store_spr(SPR_PPE42_EDR, cpu_gpr[a->ra]);
|
||||
|
||||
t8 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_concat_tl_i64(t8, cpu_gpr[31], cpu_gpr[30]);
|
||||
tcg_gen_addi_tl(EA, cpu_gpr[a->ra], -8);
|
||||
tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
|
||||
tcg_gen_concat_tl_i64(t8, cpu_gpr[29], cpu_gpr[28]);
|
||||
tcg_gen_addi_tl(EA, EA, -8);
|
||||
tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
|
||||
lo = tcg_temp_new();
|
||||
hi = tcg_temp_new();
|
||||
|
||||
gen_load_spr(hi, SPR_SRR0);
|
||||
gen_load_spr(lo, SPR_SRR1);
|
||||
tcg_gen_concat_tl_i64(t8, lo, hi);
|
||||
tcg_gen_addi_tl(EA, EA, -8);
|
||||
tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
|
||||
gen_get_xer(ctx, hi);
|
||||
tcg_gen_mov_tl(lo, cpu_ctr);
|
||||
tcg_gen_concat_tl_i64(t8, lo, hi);
|
||||
tcg_gen_addi_tl(EA, EA, -8);
|
||||
tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
|
||||
for (i = 0; i < sizeof(vd_list); i++) {
|
||||
int vd = vd_list[i];
|
||||
tcg_gen_concat_tl_i64(t8, cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd]);
|
||||
tcg_gen_addi_tl(EA, EA, -8);
|
||||
tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
}
|
||||
|
||||
gen_load_spr(lo, SPR_SPRG0);
|
||||
tcg_gen_extu_i32_tl(hi, cpu_crf[0]);
|
||||
tcg_gen_shli_tl(hi, hi, 28);
|
||||
tcg_gen_concat_tl_i64(t8, lo, hi);
|
||||
tcg_gen_addi_tl(EA, EA, -8);
|
||||
tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
|
||||
tcg_gen_addi_tl(EA, cpu_gpr[a->ra], a->si * 8);
|
||||
tcg_gen_qemu_st_tl(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) |
|
||||
MO_ALIGN);
|
||||
tcg_gen_mov_tl(cpu_gpr[a->ra], EA);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_STSKU(DisasContext *ctx, arg_STSKU *a)
|
||||
{
|
||||
int64_t n;
|
||||
TCGv base, EA;
|
||||
TCGv lo, hi;
|
||||
TCGv_i64 t8;
|
||||
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
|
||||
CHECK_PPE_GPR(ctx, a->rt);
|
||||
|
||||
if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) {
|
||||
gen_invalid(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
EA = tcg_temp_new();
|
||||
base = tcg_temp_new();
|
||||
gen_addr_register(ctx, base);
|
||||
tcg_gen_addi_tl(EA, base, 4);
|
||||
tcg_gen_qemu_st_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
|
||||
|
||||
gen_store_spr(SPR_PPE42_EDR, base);
|
||||
|
||||
n = ~(a->si);
|
||||
|
||||
t8 = tcg_temp_new_i64();
|
||||
if (n > 0) {
|
||||
hi = cpu_gpr[30];
|
||||
lo = cpu_gpr[31];
|
||||
tcg_gen_concat_tl_i64(t8, lo, hi);
|
||||
tcg_gen_addi_tl(EA, base, -8);
|
||||
tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
}
|
||||
if (n > 1) {
|
||||
hi = cpu_gpr[28];
|
||||
lo = cpu_gpr[29];
|
||||
tcg_gen_concat_tl_i64(t8, lo, hi);
|
||||
tcg_gen_addi_tl(EA, base, -16);
|
||||
tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
|
||||
}
|
||||
|
||||
tcg_gen_addi_tl(EA, base, a->si * 8);
|
||||
tcg_gen_qemu_st_tl(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) |
|
||||
MO_ALIGN);
|
||||
tcg_gen_mov_tl(cpu_gpr[a->ra], EA);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_ppe_ldst(DisasContext *ctx, int rt, int ra, TCGv disp,
|
||||
bool update, bool store)
|
||||
{
|
||||
TCGv ea;
|
||||
int rt_lo;
|
||||
TCGv_i64 t8;
|
||||
|
||||
CHECK_VDR(ctx, rt);
|
||||
CHECK_PPE_GPR(ctx, ra);
|
||||
rt_lo = VDR_PAIR_REG(rt);
|
||||
if (update && (ra == 0 || (!store && ((ra == rt) || (ra == rt_lo))))) {
|
||||
gen_invalid(ctx);
|
||||
return true;
|
||||
}
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
|
||||
ea = do_ea_calc(ctx, ra, disp);
|
||||
t8 = tcg_temp_new_i64();
|
||||
if (store) {
|
||||
tcg_gen_concat_tl_i64(t8, cpu_gpr[rt_lo], cpu_gpr[rt]);
|
||||
tcg_gen_qemu_st_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64));
|
||||
} else {
|
||||
tcg_gen_qemu_ld_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64));
|
||||
tcg_gen_extr_i64_tl(cpu_gpr[rt_lo], cpu_gpr[rt], t8);
|
||||
}
|
||||
if (update) {
|
||||
tcg_gen_mov_tl(cpu_gpr[ra], ea);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_ppe_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store)
|
||||
{
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update,
|
||||
store);
|
||||
}
|
||||
|
||||
static bool do_ppe_ldst_X(DisasContext *ctx, arg_X *a, bool store)
|
||||
{
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
CHECK_PPE_GPR(ctx, a->rb);
|
||||
return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, store);
|
||||
}
|
||||
|
||||
TRANS(LVD, do_ppe_ldst_D, false, false)
|
||||
TRANS(LVDU, do_ppe_ldst_D, true, false)
|
||||
TRANS(STVD, do_ppe_ldst_D, false, true)
|
||||
TRANS(STVDU, do_ppe_ldst_D, true, true)
|
||||
TRANS(LVDX, do_ppe_ldst_X, false)
|
||||
TRANS(STVDX, do_ppe_ldst_X, true)
|
||||
|
||||
|
||||
static bool do_fcb(DisasContext *ctx, TCGv ra_val, TCGv rb_val, int bix,
|
||||
int32_t bdx, bool s, bool px, bool lk)
|
||||
{
|
||||
TCGCond cond;
|
||||
uint32_t mask;
|
||||
TCGLabel *no_branch;
|
||||
target_ulong dest;
|
||||
|
||||
/* Update CR0 */
|
||||
gen_op_cmp32(ra_val, rb_val, s, 0);
|
||||
|
||||
if (lk) {
|
||||
gen_setlr(ctx, ctx->base.pc_next);
|
||||
}
|
||||
|
||||
|
||||
mask = PPC_BIT32(28 + bix);
|
||||
cond = (px) ? TCG_COND_TSTEQ : TCG_COND_TSTNE;
|
||||
no_branch = gen_new_label();
|
||||
dest = ctx->cia + bdx;
|
||||
|
||||
/* Do the branch if CR0[bix] == PX */
|
||||
tcg_gen_brcondi_i32(cond, cpu_crf[0], mask, no_branch);
|
||||
gen_goto_tb(ctx, 0, dest);
|
||||
gen_set_label(no_branch);
|
||||
gen_goto_tb(ctx, 1, ctx->base.pc_next);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_cmp_branch(DisasContext *ctx, arg_FCB_bix *a, bool s,
|
||||
bool rb_is_gpr)
|
||||
{
|
||||
TCGv old_ra;
|
||||
TCGv rb_val;
|
||||
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
CHECK_PPE_GPR(ctx, a->ra);
|
||||
if (rb_is_gpr) {
|
||||
CHECK_PPE_GPR(ctx, a->rb);
|
||||
rb_val = cpu_gpr[a->rb];
|
||||
} else {
|
||||
rb_val = tcg_constant_tl(a->rb);
|
||||
}
|
||||
if (a->bix == 3) {
|
||||
old_ra = tcg_temp_new();
|
||||
tcg_gen_mov_tl(old_ra, cpu_gpr[a->ra]);
|
||||
tcg_gen_sub_tl(cpu_gpr[a->ra], cpu_gpr[a->ra], rb_val);
|
||||
return do_fcb(ctx, old_ra, rb_val, 2,
|
||||
a->bdx, s, a->px, a->lk);
|
||||
} else {
|
||||
return do_fcb(ctx, cpu_gpr[a->ra], rb_val, a->bix,
|
||||
a->bdx, s, a->px, a->lk);
|
||||
}
|
||||
}
|
||||
|
||||
TRANS(CMPWBC, do_cmp_branch, true, true)
|
||||
TRANS(CMPLWBC, do_cmp_branch, false, true)
|
||||
TRANS(CMPWIBC, do_cmp_branch, true, false)
|
||||
|
||||
static bool do_mask_branch(DisasContext *ctx, arg_FCB * a, bool invert,
|
||||
bool update, bool rb_is_gpr)
|
||||
{
|
||||
TCGv r;
|
||||
TCGv mask, shift;
|
||||
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
CHECK_PPE_GPR(ctx, a->ra);
|
||||
if (rb_is_gpr) {
|
||||
CHECK_PPE_GPR(ctx, a->rb);
|
||||
mask = tcg_temp_new();
|
||||
shift = tcg_temp_new();
|
||||
tcg_gen_andi_tl(shift, cpu_gpr[a->rb], 0x1f);
|
||||
tcg_gen_shr_tl(mask, tcg_constant_tl(0x80000000), shift);
|
||||
} else {
|
||||
mask = tcg_constant_tl(PPC_BIT32(a->rb));
|
||||
}
|
||||
if (invert) {
|
||||
tcg_gen_not_tl(mask, mask);
|
||||
}
|
||||
|
||||
/* apply mask to ra */
|
||||
r = tcg_temp_new();
|
||||
tcg_gen_and_tl(r, cpu_gpr[a->ra], mask);
|
||||
if (update) {
|
||||
tcg_gen_mov_tl(cpu_gpr[a->ra], r);
|
||||
}
|
||||
return do_fcb(ctx, r, tcg_constant_tl(0), 2,
|
||||
a->bdx, false, a->px, a->lk);
|
||||
}
|
||||
|
||||
TRANS(BNBWI, do_mask_branch, false, false, false)
|
||||
TRANS(BNBW, do_mask_branch, false, false, true)
|
||||
TRANS(CLRBWIBC, do_mask_branch, true, true, false)
|
||||
TRANS(CLRBWBC, do_mask_branch, true, true, true)
|
||||
|
||||
static void gen_set_Rc0_i64(DisasContext *ctx, TCGv_i64 reg)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
TCGv_i32 t = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_movi_i64(t0, CRF_EQ);
|
||||
tcg_gen_movi_i64(t1, CRF_LT);
|
||||
tcg_gen_movcond_i64(TCG_COND_LT, t0, reg, tcg_constant_i64(0), t1, t0);
|
||||
tcg_gen_movi_i64(t1, CRF_GT);
|
||||
tcg_gen_movcond_i64(TCG_COND_GT, t0, reg, tcg_constant_i64(0), t1, t0);
|
||||
tcg_gen_extrl_i64_i32(t, t0);
|
||||
tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
|
||||
tcg_gen_or_i32(cpu_crf[0], cpu_crf[0], t);
|
||||
}
|
||||
|
||||
static bool do_shift64(DisasContext *ctx, arg_X_rc *a, bool left)
|
||||
{
|
||||
int rt_lo, ra_lo;
|
||||
TCGv_i64 t0, t8;
|
||||
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
|
||||
CHECK_VDR(ctx, a->rt);
|
||||
CHECK_VDR(ctx, a->ra);
|
||||
CHECK_PPE_GPR(ctx, a->rb);
|
||||
rt_lo = VDR_PAIR_REG(a->rt);
|
||||
ra_lo = VDR_PAIR_REG(a->ra);
|
||||
t8 = tcg_temp_new_i64();
|
||||
|
||||
/* AND rt with a mask that is 0 when rb >= 0x40 */
|
||||
t0 = tcg_temp_new_i64();
|
||||
tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]);
|
||||
tcg_gen_shli_i64(t0, t0, 0x39);
|
||||
tcg_gen_sari_i64(t0, t0, 0x3f);
|
||||
|
||||
/* form 64bit value from two 32bit regs */
|
||||
tcg_gen_concat_tl_i64(t8, cpu_gpr[rt_lo], cpu_gpr[a->rt]);
|
||||
|
||||
/* apply mask */
|
||||
tcg_gen_andc_i64(t8, t8, t0);
|
||||
|
||||
/* do the shift */
|
||||
tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]);
|
||||
tcg_gen_andi_i64(t0, t0, 0x3f);
|
||||
if (left) {
|
||||
tcg_gen_shl_i64(t8, t8, t0);
|
||||
} else {
|
||||
tcg_gen_shr_i64(t8, t8, t0);
|
||||
}
|
||||
|
||||
/* split the 64bit word back into two 32bit regs */
|
||||
tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8);
|
||||
|
||||
/* update CR0 if requested */
|
||||
if (unlikely(a->rc != 0)) {
|
||||
gen_set_Rc0_i64(ctx, t8);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TRANS(SRVD, do_shift64, false)
|
||||
TRANS(SLVD, do_shift64, true)
|
||||
|
||||
static bool trans_DCBQ(DisasContext *ctx, arg_DCBQ * a)
|
||||
{
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CHECK_PPE_GPR(ctx, a->rt);
|
||||
CHECK_PPE_GPR(ctx, a->ra);
|
||||
CHECK_PPE_GPR(ctx, a->rb);
|
||||
|
||||
/* No cache exists, so just set RT to 0 */
|
||||
tcg_gen_movi_tl(cpu_gpr[a->rt], 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_RLDIMI(DisasContext *ctx, arg_RLDIMI *a)
|
||||
{
|
||||
TCGv_i64 t_rs, t_ra;
|
||||
int ra_lo, rs_lo;
|
||||
uint32_t sh = a->sh;
|
||||
uint32_t mb = a->mb;
|
||||
uint32_t me = 63 - sh;
|
||||
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
|
||||
CHECK_VDR(ctx, a->rs);
|
||||
CHECK_VDR(ctx, a->ra);
|
||||
|
||||
rs_lo = VDR_PAIR_REG(a->rs);
|
||||
ra_lo = VDR_PAIR_REG(a->ra);
|
||||
|
||||
t_rs = tcg_temp_new_i64();
|
||||
t_ra = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_concat_tl_i64(t_rs, cpu_gpr[rs_lo], cpu_gpr[a->rs]);
|
||||
tcg_gen_concat_tl_i64(t_ra, cpu_gpr[ra_lo], cpu_gpr[a->ra]);
|
||||
|
||||
if (mb <= me) {
|
||||
tcg_gen_deposit_i64(t_ra, t_ra, t_rs, sh, me - mb + 1);
|
||||
} else {
|
||||
uint64_t mask = mask_u64(mb, me);
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_rotli_i64(t1, t_rs, sh);
|
||||
tcg_gen_andi_i64(t1, t1, mask);
|
||||
tcg_gen_andi_i64(t_ra, t_ra, ~mask);
|
||||
tcg_gen_or_i64(t_ra, t_ra, t1);
|
||||
}
|
||||
|
||||
tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t_ra);
|
||||
|
||||
if (unlikely(a->rc != 0)) {
|
||||
gen_set_Rc0_i64(ctx, t_ra);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool gen_rldinm_i64(DisasContext *ctx, arg_MD *a, int mb, int me, int sh)
|
||||
{
|
||||
int len = me - mb + 1;
|
||||
int rsh = (64 - sh) & 63;
|
||||
int ra_lo, rs_lo;
|
||||
TCGv_i64 t8;
|
||||
|
||||
if (unlikely(!is_ppe(ctx))) {
|
||||
return false;
|
||||
}
|
||||
CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
|
||||
CHECK_VDR(ctx, a->rs);
|
||||
CHECK_VDR(ctx, a->ra);
|
||||
|
||||
rs_lo = VDR_PAIR_REG(a->rs);
|
||||
ra_lo = VDR_PAIR_REG(a->ra);
|
||||
t8 = tcg_temp_new_i64();
|
||||
tcg_gen_concat_tl_i64(t8, cpu_gpr[rs_lo], cpu_gpr[a->rs]);
|
||||
if (sh != 0 && len > 0 && me == (63 - sh)) {
|
||||
tcg_gen_deposit_z_i64(t8, t8, sh, len);
|
||||
} else if (me == 63 && rsh + len <= 64) {
|
||||
tcg_gen_extract_i64(t8, t8, rsh, len);
|
||||
} else {
|
||||
tcg_gen_rotli_i64(t8, t8, sh);
|
||||
tcg_gen_andi_i64(t8, t8, mask_u64(mb, me));
|
||||
}
|
||||
tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8);
|
||||
if (unlikely(a->rc != 0)) {
|
||||
gen_set_Rc0_i64(ctx, t8);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TRANS(RLDICL, gen_rldinm_i64, a->mb, 63, a->sh)
|
||||
TRANS(RLDICR, gen_rldinm_i64, 0, a->mb, a->sh)
|
||||
@@ -15,6 +15,7 @@ tests_ppc_system_thorough = [
|
||||
'bamboo',
|
||||
'mac',
|
||||
'mpc8544ds',
|
||||
'ppe42',
|
||||
'replay',
|
||||
'sam460ex',
|
||||
'tuxrun',
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Functional tests for the IBM PPE42 processor
|
||||
#
|
||||
# Copyright (c) 2025, IBM Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
from qemu_test import QemuSystemTest, Asset
|
||||
import asyncio
|
||||
|
||||
class Ppe42Machine(QemuSystemTest):
|
||||
|
||||
timeout = 90
|
||||
poll_period = 1.0
|
||||
|
||||
ASSET_PPE42_TEST_IMAGE = Asset(
|
||||
('https://github.com/milesg-github/ppe42-tests/raw/refs/heads/main/'
|
||||
'images/ppe42-test.out'),
|
||||
'03c1ac0fb7f6c025102a02776a93b35101dae7c14b75e4eab36a337e39042ea8')
|
||||
|
||||
def _test_completed(self):
|
||||
self.log.info("Checking for test completion...")
|
||||
try:
|
||||
output = self.vm.cmd('human-monitor-command',
|
||||
command_line='info registers')
|
||||
except Exception as err:
|
||||
self.log.debug(f"'info registers' cmd failed due to {err=},"
|
||||
" {type(err)=}")
|
||||
raise
|
||||
|
||||
self.log.info(output)
|
||||
if "NIP fff80200" in output:
|
||||
self.log.info("<test completed>")
|
||||
return True
|
||||
else:
|
||||
self.log.info("<test not completed>")
|
||||
return False
|
||||
|
||||
def _wait_pass_fail(self, timeout):
|
||||
while not self._test_completed():
|
||||
if timeout >= self.poll_period:
|
||||
timeout = timeout - self.poll_period
|
||||
self.log.info(f"Waiting {self.poll_period} seconds for test"
|
||||
" to complete...")
|
||||
e = None
|
||||
try:
|
||||
e = self.vm.event_wait('STOP', self.poll_period)
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
self.log.info("Poll period ended.")
|
||||
pass
|
||||
|
||||
except Exception as err:
|
||||
self.log.debug(f"event_wait() failed due to {err=},"
|
||||
" {type(err)=}")
|
||||
raise
|
||||
|
||||
if e != None:
|
||||
self.log.debug(f"Execution stopped: {e}")
|
||||
self.log.debug("Exiting due to test failure")
|
||||
self.fail("Failure detected!")
|
||||
break
|
||||
else:
|
||||
self.fail("Timed out waiting for test completion.")
|
||||
|
||||
def test_ppe42_instructions(self):
|
||||
self.set_machine('ppe42_machine')
|
||||
self.require_accelerator("tcg")
|
||||
image_path = self.ASSET_PPE42_TEST_IMAGE.fetch()
|
||||
self.vm.add_args('-nographic')
|
||||
self.vm.add_args('-device', f'loader,file={image_path}')
|
||||
self.vm.add_args('-device', 'loader,addr=0xfff80040,cpu-num=0')
|
||||
self.vm.add_args('-action', 'panic=pause')
|
||||
self.vm.launch()
|
||||
self._wait_pass_fail(self.timeout)
|
||||
|
||||
if __name__ == '__main__':
|
||||
QemuSystemTest.main()
|
||||
@@ -18,9 +18,14 @@ class powernvMachine(LinuxKernelTest):
|
||||
good_message = 'VFS: Cannot open root device'
|
||||
|
||||
ASSET_KERNEL = Asset(
|
||||
('https://archives.fedoraproject.org/pub/archive/fedora-secondary/'
|
||||
'releases/29/Everything/ppc64le/os/ppc/ppc64/vmlinuz'),
|
||||
'383c2f5c23bc0d9d32680c3924d3fd7ee25cc5ef97091ac1aa5e1d853422fc5f')
|
||||
('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/'
|
||||
'buildroot/qemu_ppc64le_powernv8-2025.02/vmlinux'),
|
||||
'6fd29aff9ad4362511ea5d0acbb510667c7031928e97d64ec15bbc5daf4b8151')
|
||||
|
||||
ASSET_INITRD = Asset(
|
||||
('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/'
|
||||
'buildroot/qemu_ppc64le_powernv8-2025.02/rootfs.ext2'),
|
||||
'aee2192b692077c4bde31cb56ce474424b358f17cec323d5c94af3970c9aada2')
|
||||
|
||||
def do_test_linux_boot(self, command_line = KERNEL_COMMON_COMMAND_LINE):
|
||||
self.require_accelerator("tcg")
|
||||
@@ -78,27 +83,24 @@ class powernvMachine(LinuxKernelTest):
|
||||
wait_for_console_pattern(self, console_pattern, self.panic_message)
|
||||
wait_for_console_pattern(self, self.good_message, self.panic_message)
|
||||
|
||||
|
||||
ASSET_EPAPR_KERNEL = Asset(
|
||||
('https://github.com/open-power/op-build/releases/download/v2.7/'
|
||||
'zImage.epapr'),
|
||||
'0ab237df661727e5392cee97460e8674057a883c5f74381a128fa772588d45cd')
|
||||
|
||||
def do_test_ppc64_powernv(self, proc):
|
||||
self.require_accelerator("tcg")
|
||||
kernel_path = self.ASSET_EPAPR_KERNEL.fetch()
|
||||
kernel_path = self.ASSET_KERNEL.fetch()
|
||||
initrd_path = self.ASSET_INITRD.fetch()
|
||||
self.vm.set_console()
|
||||
self.vm.add_args('-kernel', kernel_path,
|
||||
'-append', 'console=tty0 console=hvc0',
|
||||
'-drive',
|
||||
f'file={initrd_path},format=raw,if=none,id=drive0,readonly=on',
|
||||
'-append', 'root=/dev/nvme0n1 console=tty0 console=hvc0',
|
||||
'-device', 'pcie-pci-bridge,id=bridge1,bus=pcie.1,addr=0x0',
|
||||
'-device', 'nvme,bus=pcie.2,addr=0x0,serial=1234',
|
||||
'-device', 'nvme,drive=drive0,bus=pcie.2,addr=0x0,serial=1234',
|
||||
'-device', 'e1000e,bus=bridge1,addr=0x3',
|
||||
'-device', 'nec-usb-xhci,bus=bridge1,addr=0x2')
|
||||
self.vm.launch()
|
||||
|
||||
self.wait_for_console_pattern("CPU: " + proc + " generation processor")
|
||||
self.wait_for_console_pattern("zImage starting: loaded")
|
||||
self.wait_for_console_pattern("Run /init as init process")
|
||||
self.wait_for_console_pattern("INIT: Starting kernel at ")
|
||||
self.wait_for_console_pattern("Run /sbin/init as init process")
|
||||
# Device detection output driven by udev probing is sometimes cut off
|
||||
# from console output, suspect S14silence-console init script.
|
||||
|
||||
@@ -114,5 +116,9 @@ class powernvMachine(LinuxKernelTest):
|
||||
self.set_machine('powernv10')
|
||||
self.do_test_ppc64_powernv('P10')
|
||||
|
||||
def test_powernv11(self):
|
||||
self.set_machine('powernv11')
|
||||
self.do_test_ppc64_powernv('Power11')
|
||||
|
||||
if __name__ == '__main__':
|
||||
LinuxKernelTest.main()
|
||||
|
||||
Reference in New Issue
Block a user