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

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


Reply via email to