On Wed, 2025-09-24 at 18:02 +0530, Chinmay Rath wrote:
> On 9/18/25 23:57, Glenn Miles wrote:
> > Adds the IBM PPE42 family of 32-bit processors supporting
> > the PPE42, PPE42X and PPE42XM processor versions. These
> > processors are used as embedded processors in the IBM
> > Power9, Power10 and Power12 processors for various
> > tasks. It is basically a stripped down version of the
> > IBM PowerPC 405 processor, with some added instructions
> > for handling 64-bit loads and stores.
> >
> > For more information on the PPE 42 processor please visit:
> >
> > https://wiki.raptorcs.com/w/images/a/a3/PPE_42X_Core_Users_Manual.pdf
> >
> > Supports PPE42 SPR's (Including the MSR).
> >
> > Does not yet support exceptions, new PPE42 instructions and
> > does not prevent access to some invalid instructions and
> > registers (currently allows access to invalid GPR's and CR
> > fields).
> >
> > Signed-off-by: Glenn Miles <[email protected]>
> > ---
> > target/ppc/cpu-models.c | 7 ++
> > target/ppc/cpu_init.c | 204 ++++++++++++++++++++++++++++++++-------
> > target/ppc/helper_regs.c | 41 +++++---
> > target/ppc/translate.c | 6 +-
> > 4 files changed, 203 insertions(+), 55 deletions(-)
> >
> > diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c
> > index ea86ea202a..09f73e23a8 100644
> > --- a/target/ppc/cpu-models.c
> > +++ b/target/ppc/cpu-models.c
> > @@ -116,6 +116,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,
> > diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> > index db841f1260..b42673c6b5 100644
> > --- a/target/ppc/cpu_init.c
> > +++ b/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)
> > @@ -2200,6 +2241,79 @@ 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);
> > +
> > + 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_40x;
> > + 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 +6916,63 @@ 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)) {
>
> Hey Glenn,
>
> Did you miss adding the POWERPC_FLAG_PPE42 flag here ^ ?
>
> Thanks,
> Chinmay
No. All PPE42 processors will have bit 1 << 25 set in env->msr_mask, so
it will always fall into the previous condition block and never enter
the 2nd check.
Glenn
>
> > 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 +6991,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) {
> > @@ -7243,39 +7372,40 @@ static void ppc_cpu_reset_hold(Object *obj,
> > ResetType type)
> > }
> >
> > msr = (target_ulong)0;
> > - msr |= (target_ulong)MSR_HVB;
> > - msr |= (target_ulong)1 << MSR_EP;
> > + if (!(env->flags & POWERPC_FLAG_PPE42)) {
> > + msr |= (target_ulong)MSR_HVB;
> > + msr |= (target_ulong)1 << MSR_EP;
> > #if defined(DO_SINGLE_STEP) && 0
> > - /* Single step trace mode */
> > - msr |= (target_ulong)1 << MSR_SE;
> > - msr |= (target_ulong)1 << MSR_BE;
> > + /* Single step trace mode */
> > + msr |= (target_ulong)1 << MSR_SE;
> > + msr |= (target_ulong)1 << MSR_BE;
> > #endif
> > #if defined(CONFIG_USER_ONLY)
> > - msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
> > - msr |= (target_ulong)1 << MSR_FE0; /* Allow floating point exceptions
> > */
> > - msr |= (target_ulong)1 << MSR_FE1;
> > - msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
> > - msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */
> > - msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
> > - msr |= (target_ulong)1 << MSR_PR;
> > + msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
> > + msr |= (target_ulong)1 << MSR_FE0; /* Allow floating point
> > exceptions */
> > + msr |= (target_ulong)1 << MSR_FE1;
> > + msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
> > + msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */
> > + msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
> > + msr |= (target_ulong)1 << MSR_PR;
> > #if defined(TARGET_PPC64)
> > - msr |= (target_ulong)1 << MSR_TM; /* Transactional memory */
> > + msr |= (target_ulong)1 << MSR_TM; /* Transactional memory */
> > #endif
> > #if !TARGET_BIG_ENDIAN
> > - msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */
> > - if (!((env->msr_mask >> MSR_LE) & 1)) {
> > - fprintf(stderr, "Selected CPU does not support little-endian.\n");
> > - exit(1);
> > - }
> > + msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */
> > + if (!((env->msr_mask >> MSR_LE) & 1)) {
> > + fprintf(stderr, "Selected CPU does not support
> > little-endian.\n");
> > + exit(1);
> > + }
> > #endif
> > #endif
> >
> > #if defined(TARGET_PPC64)
> > - if (mmu_is_64bit(env->mmu_model)) {
> > - msr |= (1ULL << MSR_SF);
> > - }
> > + if (mmu_is_64bit(env->mmu_model)) {
> > + msr |= (1ULL << MSR_SF);
> > + }
> > #endif
> > -
> > + }
> > hreg_store_msr(env, msr, 1);
> >
> > #if !defined(CONFIG_USER_ONLY)
> > diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
> > index 5f21739749..41b7b939ec 100644
> > --- a/target/ppc/helper_regs.c
> > +++ b/target/ppc/helper_regs.c
> > @@ -308,9 +308,6 @@ int hreg_store_msr(CPUPPCState *env, target_ulong
> > value, int alter_hv)
> > value &= ~(1 << MSR_ME);
> > value |= env->msr & (1 << MSR_ME);
> > }
> > - if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) {
> > - cpu_interrupt_exittb(cs);
> > - }
> > if ((env->mmu_model == POWERPC_MMU_BOOKE ||
> > env->mmu_model == POWERPC_MMU_BOOKE206) &&
> > ((value ^ env->msr) & R_MSR_GS_MASK)) {
> > @@ -321,8 +318,14 @@ int hreg_store_msr(CPUPPCState *env, target_ulong
> > value, int alter_hv)
> > /* Swap temporary saved registers with GPRs */
> > hreg_swap_gpr_tgpr(env);
> > }
> > - if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) {
> > - env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000;
> > + /* PPE42 uses IR, DR and EP MSR bits for other purposes */
> > + if (likely(!(env->flags & POWERPC_FLAG_PPE42))) {
> > + if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) {
> > + cpu_interrupt_exittb(cs);
> > + }
> > + if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) {
> > + env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000;
> > + }
> > }
> > /*
> > * If PR=1 then EE, IR and DR must be 1
> > @@ -464,6 +467,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 +497,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) {
> > diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> > index 27f90c3cc5..fc817dab54 100644
> > --- a/target/ppc/translate.c
> > +++ b/target/ppc/translate.c
> > @@ -4264,8 +4264,10 @@ static void gen_mtmsr(DisasContext *ctx)
> > /* L=1 form only updates EE and RI */
> > mask &= (1ULL << MSR_RI) | (1ULL << MSR_EE);
> > } else {
> > - /* mtmsr does not alter S, ME, or LE */
> > - mask &= ~((1ULL << MSR_LE) | (1ULL << MSR_ME) | (1ULL << MSR_S));
> > + if (likely(!(ctx->insns_flags2 & PPC2_PPE42))) {
> > + /* mtmsr does not alter S, ME, or LE */
> > + mask &= ~((1ULL << MSR_LE) | (1ULL << MSR_ME) | (1ULL <<
> > MSR_S));
> > + }
> >
> > /*
> > * XXX: we need to update nip before the store if we enter