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 <milesg@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)) {
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
--
2.43.0
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 <milesg@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
> 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
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 <milesg@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
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 <milesg@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
Hi Glenn,
On 9/24/25 20:36, Miles Glenn wrote:
>>>> @@ -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.
While we are at it, can we also replace all hard-coded bit shifts with
appropriate macros which reflect what these shifts are about. There are
few more such checks in the patch. May be audit other patches as well
for such instances.
regards
Harsh
>
> Thanks,
>
> Glenn
On Thu, 2025-09-25 at 10:27 +0530, Harsh Prateek Bora wrote:
> Hi Glenn,
>
> On 9/24/25 20:36, Miles Glenn wrote:
> > > > > @@ -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.
>
> While we are at it, can we also replace all hard-coded bit shifts with
> appropriate macros which reflect what these shifts are about. There are
> few more such checks in the patch. May be audit other patches as well
> for such instances.
>
> regards
> Harsh
>
Hi Harsh,
Normally I would agree with you, but I think that all of the hard-coded
bit shifts in this function (init_ppc_proc) are hard-coded because the
MSR bits have multiple meanings depending on the CPU and this function
is called on all PPC CPUs. So, in this context, I think that using the
hard-coded bit number is appropriate and this is probably why it has
remained as a hard-coded value in this function since 2007.
That being said, if you still feel strongly that these hard-coded
values should be replaced with macros, could you provide suggestions on
what would be appropriate names in this function?
Thanks,
Glenn
> > Thanks,
> >
> > Glenn
On 9/25/25 20:59, Miles Glenn wrote:
> On Thu, 2025-09-25 at 10:27 +0530, Harsh Prateek Bora wrote:
>> Hi Glenn,
>>
>> On 9/24/25 20:36, Miles Glenn wrote:
>>>>>> @@ -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.
>>
>> While we are at it, can we also replace all hard-coded bit shifts with
>> appropriate macros which reflect what these shifts are about. There are
>> few more such checks in the patch. May be audit other patches as well
>> for such instances.
>>
>> regards
>> Harsh
>>
>
> Hi Harsh,
>
> Normally I would agree with you, but I think that all of the hard-coded
> bit shifts in this function (init_ppc_proc) are hard-coded because the
> MSR bits have multiple meanings depending on the CPU and this function
> is called on all PPC CPUs. So, in this context, I think that using the
> hard-coded bit number is appropriate and this is probably why it has
> remained as a hard-coded value in this function since 2007.
Oh I see, in that case, let's keep it as-is.
Thanks
Harsh
>
> That being said, if you still feel strongly that these hard-coded
> values should be replaced with macros, could you provide suggestions on
> what would be appropriate names in this function?
>
> Thanks,
>
> Glenn
>
>
>>> Thanks,
>>>
>>> Glenn
>
© 2016 - 2025 Red Hat, Inc.