Browse Source

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

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>
pull/305/head
Richard Henderson 6 months ago
parent
commit
9b16edec6e
  1. 7
      MAINTAINERS
  2. 9
      docs/about/deprecated.rst
  3. 9
      docs/system/ppc/powernv.rst
  4. 4
      hw/intc/pnv_xive2.c
  5. 2
      hw/intc/xics.c
  6. 45
      hw/intc/xive2.c
  7. 5
      hw/ppc/Kconfig
  8. 2
      hw/ppc/meson.build
  9. 560
      hw/ppc/pnv.c
  10. 59
      hw/ppc/pnv_chiptod.c
  11. 17
      hw/ppc/pnv_core.c
  12. 5
      hw/ppc/ppc_booke.c
  13. 101
      hw/ppc/ppe42_machine.c
  14. 7
      hw/ppc/spapr.c
  15. 38
      include/hw/ppc/pnv.h
  16. 8
      include/hw/ppc/pnv_chip.h
  17. 2
      include/hw/ppc/pnv_chiptod.h
  18. 49
      include/hw/ppc/pnv_xscom.h
  19. 1
      include/hw/ppc/ppc.h
  20. 27
      target/ppc/cpu-models.c
  21. 4
      target/ppc/cpu-models.h
  22. 76
      target/ppc/cpu.h
  23. 207
      target/ppc/cpu_init.c
  24. 163
      target/ppc/excp_helper.c
  25. 38
      target/ppc/fpu_helper.c
  26. 38
      target/ppc/helper.h
  27. 41
      target/ppc/helper_regs.c
  28. 106
      target/ppc/insn32.decode
  29. 12
      target/ppc/tcg-excp_helper.c
  30. 31
      target/ppc/translate.c
  31. 291
      target/ppc/translate/fp-impl.c.inc
  32. 30
      target/ppc/translate/fp-ops.c.inc
  33. 609
      target/ppc/translate/ppe-impl.c.inc
  34. 1
      tests/functional/ppc/meson.build
  35. 79
      tests/functional/ppc/test_ppe42.py
  36. 34
      tests/functional/ppc64/test_powernv.py

7
MAINTAINERS

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

9
docs/about/deprecated.rst

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

9
docs/system/ppc/powernv.rst

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

4
hw/intc/pnv_xive2.c

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

2
hw/intc/xics.c

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

45
hw/intc/xive2.c

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

5
hw/ppc/Kconfig

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

2
hw/ppc/meson.build

@ -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
hw/ppc/pnv.c

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

59
hw/ppc/pnv_chiptod.c

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

17
hw/ppc/pnv_core.c

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

5
hw/ppc/ppc_booke.c

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

101
hw/ppc/ppe42_machine.c

@ -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
hw/ppc/spapr.c

@ -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,12 +918,14 @@ 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);
} 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"));

38
include/hw/ppc/pnv.h

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

8
include/hw/ppc/pnv_chip.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);

2
include/hw/ppc/pnv_chiptod.h

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

49
include/hw/ppc/pnv_xscom.h

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

1
include/hw/ppc/ppc.h

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

27
target/ppc/cpu-models.c

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

4
target/ppc/cpu-models.h

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

76
target/ppc/cpu.h

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

207
target/ppc/cpu_init.c

@ -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);
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,6 +7403,7 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
}
msr = (target_ulong)0;
if (!(env->flags & POWERPC_FLAG_PPE42)) {
msr |= (target_ulong)MSR_HVB;
msr |= (target_ulong)1 << MSR_EP;
#if defined(DO_SINGLE_STEP) && 0
@ -7275,7 +7436,7 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
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",

163
target/ppc/excp_helper.c

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

38
target/ppc/fpu_helper.c

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

38
target/ppc/helper.h

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

41
target/ppc/helper_regs.c

@ -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,9 +322,15 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv)
/* Swap temporary saved registers with GPRs */
hreg_swap_gpr_tgpr(env);
}
/* 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) {

106
target/ppc/insn32.decode

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

12
target/ppc/tcg-excp_helper.c

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

31
target/ppc/translate.c

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

291
target/ppc/translate/fp-impl.c.inc

@ -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);
/* 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, 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);
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();
TCGv_i64 t0, t1, t2;
REQUIRE_INSNS_FLAGS2(ctx, VSX207);
REQUIRE_FPU(ctx);
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);
t2 = tcg_temp_new_i64();
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 void gen_fmrgow(DisasContext *ctx)
static bool trans_FMRGOW(DisasContext *ctx, arg_FMRGOW *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, 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(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

30
target/ppc/translate/fp-ops.c.inc

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

609
target/ppc/translate/ppe-impl.c.inc

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

1
tests/functional/ppc/meson.build

@ -15,6 +15,7 @@ tests_ppc_system_thorough = [
'bamboo',
'mac',
'mpc8544ds',
'ppe42',
'replay',
'sam460ex',
'tuxrun',

79
tests/functional/ppc/test_ppe42.py

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

34
tests/functional/ppc64/test_powernv.py

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

Loading…
Cancel
Save