On Wed, 2025-09-24 at 09:52 -0500, Miles Glenn wrote: > 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 <mil...@linux.ibm.com> > > > --- > > > 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 >
Ah, sorry, I should have looked closer! This is supposed to be checking that if 1 << 25 is not set that we shouldn't be setting the PPE42 flag either. So, yes, I'll add that in v6. Thanks, 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