* [PATCH v2 0/4] Add IBM PPE42 CPU support
@ 2025-08-26 20:17 Glenn Miles
2025-08-26 20:17 ` [PATCH v2 1/4] target/ppc: Add IBM PPE42 family of processors Glenn Miles
` (3 more replies)
0 siblings, 4 replies; 14+ messages in thread
From: Glenn Miles @ 2025-08-26 20:17 UTC (permalink / raw)
To: qemu-devel
Cc: Glenn Miles, qemu-ppc, clg, npiggin, harshpb, thuth, rathc,
richard.henderson
v2:
Patch 1:
- Added "32-bit" wording to commit message
- Added 'unlikely' specifier to hreg_compute_hflags_value conditional
- Added PPE42_ prefix to ISR definitions
- Moved ISR_MCS* definitions from excp_helper.c to cpu.h
- Moved common target/ppc/cpu_init.c code to a common function
- Added 'likely' specifier to gen_mtmsr conditional
- Formatting changes to fit comments within 80 character limit
Patch 3:
- Added hw/ppc/ppe42_machine.c to MAINTAINERS (myself as maintainer)
Patch 4:
- Added tests/functional/test_ppc_ppe42.py to MAINTAINERS file
This patchset adds support for the IBM PPE42 processor,
including a simple machine providing a platform for
testing the PPE42 instructions.
The PPE42 processor is used as an embedded processor 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 and some 64-bit
logical operations.
For more information on the PPE 42 processor please visit:
https://wiki.raptorcs.com/w/images/a/a3/PPE_42X_Core_Users_Manual.pdf
A functional test is included. This test downloads a
prebuilt test image from:
https://github.com/milesg-github/ppe42-tests
Building the image rquires a forked version of an old
version of GCC, which can be found here:
https://github.com/open-power/ppe42-gcc
Thanks,
Glenn
Glenn Miles (4):
target/ppc: Add IBM PPE42 family of processors
target/ppc: Add IBM PPE42 special instructions
hw/ppc: Add a test machine for the IBM PPE42 CPU
tests/functional: Add test for IBM PPE42 instructions
MAINTAINERS | 7 +
hw/ppc/Kconfig | 9 +
hw/ppc/meson.build | 2 +
hw/ppc/ppc_booke.c | 7 +-
hw/ppc/ppe42_machine.c | 69 +++
include/hw/ppc/ppc.h | 1 +
target/ppc/cpu-models.c | 7 +
target/ppc/cpu-models.h | 4 +
target/ppc/cpu.h | 76 ++-
target/ppc/cpu_init.c | 241 +++++++--
target/ppc/excp_helper.c | 163 ++++++
target/ppc/helper_regs.c | 28 +-
target/ppc/insn32.decode | 66 ++-
target/ppc/tcg-excp_helper.c | 12 +
target/ppc/translate.c | 35 +-
target/ppc/translate/ppe-impl.c.inc | 805 ++++++++++++++++++++++++++++
tests/functional/meson.build | 1 +
tests/functional/test_ppc_ppe42.py | 79 +++
18 files changed, 1556 insertions(+), 56 deletions(-)
create mode 100644 hw/ppc/ppe42_machine.c
create mode 100644 target/ppc/translate/ppe-impl.c.inc
create mode 100644 tests/functional/test_ppc_ppe42.py
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 1/4] target/ppc: Add IBM PPE42 family of processors
2025-08-26 20:17 [PATCH v2 0/4] Add IBM PPE42 CPU support Glenn Miles
@ 2025-08-26 20:17 ` Glenn Miles
2025-09-01 7:29 ` Cédric Le Goater
2025-08-26 20:17 ` [PATCH v2 2/4] target/ppc: Add IBM PPE42 special instructions Glenn Miles
` (2 subsequent siblings)
3 siblings, 1 reply; 14+ messages in thread
From: Glenn Miles @ 2025-08-26 20:17 UTC (permalink / raw)
To: qemu-devel
Cc: Glenn Miles, qemu-ppc, clg, npiggin, harshpb, thuth, rathc,
richard.henderson
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) and Exceptions.
Does not yet support new PPE42 instructions and does not
prevent access to some invalid instructions and registers
(currently allows for access to invalid GPR's and CR fields).
Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
---
Changes since previous version
- Added "32-bit" wording to commit message
- Added 'unlikely' specifier to hreg_compute_hflags_value conditional
- Added PPE42_ prefix to ISR definitions
- Moved ISR_MCS* definitions from excp_helper.c to cpu.h
- Moved common cpu_init code to a common function
- Added 'likely' specifier to gen_mtmsr conditional
- Formatting changes to fit comments within 80 character limit
target/ppc/cpu-models.c | 7 +
target/ppc/cpu-models.h | 4 +
target/ppc/cpu.h | 76 ++++++++++-
target/ppc/cpu_init.c | 241 +++++++++++++++++++++++++++++------
target/ppc/excp_helper.c | 163 +++++++++++++++++++++++
target/ppc/helper_regs.c | 28 +++-
target/ppc/tcg-excp_helper.c | 12 ++
target/ppc/translate.c | 6 +-
8 files changed, 492 insertions(+), 45 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-models.h b/target/ppc/cpu-models.h
index 72ad31ba50..c6cd27f390 100644
--- a/target/ppc/cpu-models.h
+++ b/target/ppc/cpu-models.h
@@ -69,6 +69,10 @@ enum {
/* Xilinx cores */
CPU_POWERPC_X2VP4 = 0x20010820,
CPU_POWERPC_X2VP20 = 0x20010860,
+ /* IBM PPE42 Family */
+ CPU_POWERPC_PPE42 = 0x42000000,
+ CPU_POWERPC_PPE42X = 0x42100000,
+ CPU_POWERPC_PPE42XM = 0x42200000,
/* PowerPC 440 family */
/* Generic PowerPC 440 */
#define CPU_POWERPC_440 CPU_POWERPC_440GXf
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 6b90543811..c68dd4f141 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -220,6 +220,8 @@ typedef enum powerpc_excp_t {
POWERPC_EXCP_POWER10,
/* POWER11 exception model */
POWERPC_EXCP_POWER11,
+ /* PPE42 exception model */
+ POWERPC_EXCP_PPE42,
} powerpc_excp_t;
/*****************************************************************************/
@@ -282,6 +284,8 @@ typedef enum powerpc_input_t {
PPC_FLAGS_INPUT_POWER9,
/* Freescale RCPU bus */
PPC_FLAGS_INPUT_RCPU,
+ /* PPE42 bus */
+ PPC_FLAGS_INPUT_PPE42,
} powerpc_input_t;
#define PPC_INPUT(env) ((env)->bus_model)
@@ -433,39 +437,64 @@ typedef enum {
#define MSR_TM PPC_BIT_NR(31) /* Transactional Memory Available (Book3s) */
#define MSR_CM PPC_BIT_NR(32) /* Computation mode for BookE hflags */
#define MSR_ICM PPC_BIT_NR(33) /* Interrupt computation mode for BookE */
+#define MSR_SEM0 PPC_BIT_NR(33) /* SIB Error Mask Bit 0 (PPE42) */
+#define MSR_SEM1 PPC_BIT_NR(34) /* SIB Error Mask Bit 1 (PPE42) */
+#define MSR_SEM2 PPC_BIT_NR(35) /* SIB Error Mask Bit 2 (PPE42) */
#define MSR_GS PPC_BIT_NR(35) /* guest state for BookE */
+#define MSR_SEM3 PPC_BIT_NR(36) /* SIB Error Mask Bit 3 (PPE42) */
+#define MSR_SEM4 PPC_BIT_NR(37) /* SIB Error Mask Bit 4 (PPE42) */
#define MSR_UCLE PPC_BIT_NR(37) /* User-mode cache lock enable for BookE */
#define MSR_VR PPC_BIT_NR(38) /* altivec available x hflags */
#define MSR_SPE PPC_BIT_NR(38) /* SPE enable for BookE x hflags */
+#define MSR_SEM5 PPC_BIT_NR(38) /* SIB Error Mask Bit 5 (PPE42) */
+#define MSR_SEM6 PPC_BIT_NR(39) /* SIB Error Mask Bit 6 (PPE42) */
#define MSR_VSX PPC_BIT_NR(40) /* Vector Scalar Extension (>= 2.06)x hflags */
+#define MSR_IS0 PPC_BIT_NR(40) /* Instance Specific Bit 0 (PPE42) */
#define MSR_S PPC_BIT_NR(41) /* Secure state */
+#define MSR_SIBRC0 PPC_BIT_NR(41) /* Last SIB return code Bit 0 (PPE42) */
+#define MSR_SIBRC1 PPC_BIT_NR(42) /* Last SIB return code Bit 1 (PPE42) */
+#define MSR_SIBRC2 PPC_BIT_NR(43) /* Last SIB return code Bit 2 (PPE42) */
+#define MSR_LP PPC_BIT_NR(44) /* Low Priority (PPE42) */
#define MSR_KEY PPC_BIT_NR(44) /* key bit on 603e */
#define MSR_POW PPC_BIT_NR(45) /* Power management */
#define MSR_WE PPC_BIT_NR(45) /* Wait State Enable on 405 */
+#define MSR_IS1 PPC_BIT_NR(46) /* Instance Specific Bit 1 (PPE42) */
#define MSR_TGPR PPC_BIT_NR(46) /* TGPR usage on 602/603 x */
#define MSR_CE PPC_BIT_NR(46) /* Critical int. enable on embedded PPC x */
#define MSR_ILE PPC_BIT_NR(47) /* Interrupt little-endian mode */
+#define MSR_UIE PPC_BIT_NR(47) /* Unmaskable Interrupt Enable (PPE42) */
#define MSR_EE PPC_BIT_NR(48) /* External interrupt enable */
#define MSR_PR PPC_BIT_NR(49) /* Problem state hflags */
#define MSR_FP PPC_BIT_NR(50) /* Floating point available hflags */
#define MSR_ME PPC_BIT_NR(51) /* Machine check interrupt enable */
#define MSR_FE0 PPC_BIT_NR(52) /* Floating point exception mode 0 */
+#define MSR_IS2 PPC_BIT_NR(52) /* Instance Specific Bit 2 (PPE42) */
+#define MSR_IS3 PPC_BIT_NR(53) /* Instance Specific Bit 3 (PPE42) */
#define MSR_SE PPC_BIT_NR(53) /* Single-step trace enable x hflags */
#define MSR_DWE PPC_BIT_NR(53) /* Debug wait enable on 405 x */
#define MSR_UBLE PPC_BIT_NR(53) /* User BTB lock enable on e500 x */
#define MSR_BE PPC_BIT_NR(54) /* Branch trace enable x hflags */
#define MSR_DE PPC_BIT_NR(54) /* Debug int. enable on embedded PPC x */
#define MSR_FE1 PPC_BIT_NR(55) /* Floating point exception mode 1 */
+#define MSR_IPE PPC_BIT_NR(55) /* Imprecise Mode Enable (PPE42) */
#define MSR_AL PPC_BIT_NR(56) /* AL bit on POWER */
+#define MSR_SIBRCA0 PPC_BIT_NR(56) /* SIB Return Code Accumulator 0 (PPE42) */
+#define MSR_SIBRCA1 PPC_BIT_NR(57) /* SIB Return Code Accumulator 1 (PPE42) */
#define MSR_EP PPC_BIT_NR(57) /* Exception prefix on 601 */
#define MSR_IR PPC_BIT_NR(58) /* Instruction relocate */
#define MSR_IS PPC_BIT_NR(58) /* Instruction address space (BookE) */
+#define MSR_SIBRCA2 PPC_BIT_NR(58) /* SIB Return Code Accumulator 2 (PPE42) */
+#define MSR_SIBRCA3 PPC_BIT_NR(59) /* SIB Return Code Accumulator 3 (PPE42) */
#define MSR_DR PPC_BIT_NR(59) /* Data relocate */
#define MSR_DS PPC_BIT_NR(59) /* Data address space (BookE) */
#define MSR_PE PPC_BIT_NR(60) /* Protection enable on 403 */
+#define MSR_SIBRCA4 PPC_BIT_NR(60) /* SIB Return Code Accumulator 4 (PPE42) */
+#define MSR_SIBRCA5 PPC_BIT_NR(61) /* SIB Return Code Accumulator 5 (PPE42) */
#define MSR_PX PPC_BIT_NR(61) /* Protection exclusive on 403 x */
#define MSR_PMM PPC_BIT_NR(61) /* Performance monitor mark on POWER x */
#define MSR_RI PPC_BIT_NR(62) /* Recoverable interrupt 1 */
+#define MSR_SIBRCA6 PPC_BIT_NR(62) /* SIB Return Code Accumulator 6 (PPE42) */
+#define MSR_SIBRCA7 PPC_BIT_NR(63) /* SIB Return Code Accumulator 7 (PPE42) */
#define MSR_LE PPC_BIT_NR(63) /* Little-endian mode 1 hflags */
FIELD(MSR, SF, MSR_SF, 1)
@@ -517,6 +546,9 @@ FIELD(MSR, PX, MSR_PX, 1)
FIELD(MSR, PMM, MSR_PMM, 1)
FIELD(MSR, RI, MSR_RI, 1)
FIELD(MSR, LE, MSR_LE, 1)
+FIELD(MSR, SEM, MSR_SEM6, 7)
+FIELD(MSR, SIBRC, MSR_SIBRC2, 3)
+FIELD(MSR, SIBRCA, MSR_SIBRCA7, 8)
/*
* FE0 and FE1 bits are not side-by-side
@@ -730,6 +762,31 @@ FIELD(MSR, LE, MSR_LE, 1)
#define ESR_VLEMI PPC_BIT(58) /* VLE operation */
#define ESR_MIF PPC_BIT(62) /* Misaligned instruction (VLE) */
+/* PPE42 Interrupt Status Register bits */
+#define PPE42_ISR_SRSMS0 PPC_BIT_NR(48) /* Sys Reset State Machine State 0 */
+#define PPE42_ISR_SRSMS1 PPC_BIT_NR(49) /* Sys Reset State Machine State 1 */
+#define PPE42_ISR_SRSMS2 PPC_BIT_NR(50) /* Sys Reset State Machine State 2 */
+#define PPE42_ISR_SRSMS3 PPC_BIT_NR(51) /* Sys Reset State Machine State 3 */
+#define PPE42_ISR_EP PPC_BIT_NR(53) /* MSR[EE] Maskable Event Pending */
+#define PPE42_ISR_PTR PPC_BIT_NR(56) /* Program Interrupt from trap */
+#define PPE42_ISR_ST PPC_BIT_NR(57) /* Data Interrupt caused by store */
+#define PPE42_ISR_MFE PPC_BIT_NR(60) /* Multiple Fault Error */
+#define PPE42_ISR_MCS0 PPC_BIT_NR(61) /* Machine Check Status bit0 */
+#define PPE42_ISR_MCS1 PPC_BIT_NR(62) /* Machine Check Status bit1 */
+#define PPE42_ISR_MCS2 PPC_BIT_NR(63) /* Machine Check Status bit2 */
+FIELD(PPE42_ISR, SRSMS, PPE42_ISR_SRSMS3, 4)
+FIELD(PPE42_ISR, MCS, PPE42_ISR_MCS2, 3)
+
+/* PPE42 Machine Check Status field values */
+#define PPE42_ISR_MCS_INSTRUCTION 0
+#define PPE42_ISR_MCS_DATA_LOAD 1
+#define PPE42_ISR_MCS_DATA_PRECISE_STORE 2
+#define PPE42_ISR_MCS_DATA_IMPRECISE_STORE 3
+#define PPE42_ISR_MCS_PROGRAM 4
+#define PPE42_ISR_MCS_ISI 5
+#define PPE42_ISR_MCS_ALIGNMENT 6
+#define PPE42_ISR_MCS_DSI 7
+
/* Transaction EXception And Summary Register bits */
#define TEXASR_FAILURE_PERSISTENT (63 - 7)
#define TEXASR_DISALLOWED (63 - 8)
@@ -785,6 +842,8 @@ enum {
POWERPC_FLAG_SMT_1LPAR = 0x00800000,
/* Has BHRB */
POWERPC_FLAG_BHRB = 0x01000000,
+ /* Use PPE42-specific behavior */
+ POWERPC_FLAG_PPE42 = 0x02000000,
};
/*
@@ -1750,9 +1809,12 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_BOOKE_CSRR0 (0x03A)
#define SPR_BOOKE_CSRR1 (0x03B)
#define SPR_BOOKE_DEAR (0x03D)
+#define SPR_PPE42_EDR (0x03D)
#define SPR_IAMR (0x03D)
#define SPR_BOOKE_ESR (0x03E)
+#define SPR_PPE42_ISR (0x03E)
#define SPR_BOOKE_IVPR (0x03F)
+#define SPR_PPE42_IVPR (0x03F)
#define SPR_MPC_EIE (0x050)
#define SPR_MPC_EID (0x051)
#define SPR_MPC_NRI (0x052)
@@ -1818,6 +1880,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_TBU40 (0x11E)
#define SPR_SVR (0x11E)
#define SPR_BOOKE_PIR (0x11E)
+#define SPR_PPE42_PIR (0x11E)
#define SPR_PVR (0x11F)
#define SPR_HSPRG0 (0x130)
#define SPR_BOOKE_DBSR (0x130)
@@ -1827,6 +1890,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_BOOKE_EPCR (0x133)
#define SPR_SPURR (0x134)
#define SPR_BOOKE_DBCR0 (0x134)
+#define SPR_PPE42_DBCR (0x134)
#define SPR_IBCR (0x135)
#define SPR_PURR (0x135)
#define SPR_BOOKE_DBCR1 (0x135)
@@ -1844,6 +1908,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_HSRR1 (0x13B)
#define SPR_BOOKE_IAC4 (0x13B)
#define SPR_BOOKE_DAC1 (0x13C)
+#define SPR_PPE42_DACR (0x13C)
#define SPR_MMCRH (0x13C)
#define SPR_DABR2 (0x13D)
#define SPR_BOOKE_DAC2 (0x13D)
@@ -1853,12 +1918,14 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_BOOKE_DVC2 (0x13F)
#define SPR_LPIDR (0x13F)
#define SPR_BOOKE_TSR (0x150)
+#define SPR_PPE42_TSR (0x150)
#define SPR_HMER (0x150)
#define SPR_HMEER (0x151)
#define SPR_PCR (0x152)
#define SPR_HEIR (0x153)
#define SPR_BOOKE_LPIDR (0x152)
#define SPR_BOOKE_TCR (0x154)
+#define SPR_PPE42_TCR (0x154)
#define SPR_BOOKE_TLB0PS (0x158)
#define SPR_BOOKE_TLB1PS (0x159)
#define SPR_BOOKE_TLB2PS (0x15A)
@@ -2528,6 +2595,12 @@ enum {
PPC2_MEM_LWSYNC = 0x0000000000200000ULL,
/* ISA 2.06 BCD assist instructions */
PPC2_BCDA_ISA206 = 0x0000000000400000ULL,
+ /* PPE42 instructions */
+ PPC2_PPE42 = 0x0000000000800000ULL,
+ /* PPE42X instructions */
+ PPC2_PPE42X = 0x0000000001000000ULL,
+ /* PPE42XM instructions */
+ PPC2_PPE42XM = 0x0000000002000000ULL,
#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \
PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
@@ -2537,7 +2610,8 @@ enum {
PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \
PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206 | \
PPC2_ISA300 | PPC2_ISA310 | PPC2_MEM_LWSYNC | \
- PPC2_BCDA_ISA206)
+ PPC2_BCDA_ISA206 | PPC2_PPE42 | PPC2_PPE42X | \
+ PPC2_PPE42XM)
};
/*****************************************************************************/
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index a0e77f2673..698d61bf0c 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)
@@ -1679,6 +1720,30 @@ static void init_excp_4xx(CPUPPCState *env)
#endif
}
+static void init_excp_ppe42(CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+ /* Machine Check vector changed after version 0 */
+ if (((env->spr[SPR_PVR] & 0xf00000ul) >> 20) == 0) {
+ env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000000;
+ } else {
+ env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000020;
+ }
+ env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000040;
+ env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000060;
+ env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000080;
+ env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x000000A0;
+ env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x000000C0;
+ env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x000000E0;
+ env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000100;
+ env->excp_vectors[POWERPC_EXCP_FIT] = 0x00000120;
+ env->excp_vectors[POWERPC_EXCP_WDT] = 0x00000140;
+ env->ivpr_mask = 0xFFFFFE00UL;
+ /* Hardware reset vector */
+ env->hreset_vector = 0x00000040UL;
+#endif
+}
+
static void init_excp_MPC5xx(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
@@ -2200,6 +2265,80 @@ POWERPC_FAMILY(405)(ObjectClass *oc, const void *data)
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
}
+static void init_proc_ppe42(CPUPPCState *env)
+{
+ register_ppe42_sprs(env);
+
+ init_excp_ppe42(env);
+ env->dcache_line_size = 32;
+ env->icache_line_size = 32;
+ /* Allocate hardware IRQ controller */
+ ppc40x_irq_init(env_archcpu(env));
+
+ SET_FIT_PERIOD(8, 12, 16, 20);
+ SET_WDT_PERIOD(16, 20, 24, 28);
+}
+
+static void ppe42_class_common_init(PowerPCCPUClass *pcc)
+{
+ pcc->init_proc = init_proc_ppe42;
+ pcc->check_pow = check_pow_nocheck;
+ pcc->check_attn = check_attn_none;
+ pcc->insns_flags = PPC_INSNS_BASE |
+ PPC_WRTEE |
+ PPC_CACHE |
+ PPC_CACHE_DCBZ |
+ PPC_MEM_SYNC;
+ pcc->msr_mask = R_MSR_SEM_MASK |
+ (1ull << MSR_IS0) |
+ R_MSR_SIBRC_MASK |
+ (1ull << MSR_LP) |
+ (1ull << MSR_WE) |
+ (1ull << MSR_IS1) |
+ (1ull << MSR_UIE) |
+ (1ull << MSR_EE) |
+ (1ull << MSR_ME) |
+ (1ull << MSR_IS2) |
+ (1ull << MSR_IS3) |
+ (1ull << MSR_IPE) |
+ R_MSR_SIBRCA_MASK;
+ pcc->mmu_model = POWERPC_MMU_REAL;
+ pcc->excp_model = POWERPC_EXCP_PPE42;
+ pcc->bus_model = PPC_FLAGS_INPUT_PPE42;
+ pcc->bfd_mach = bfd_mach_ppc_403;
+ pcc->flags = POWERPC_FLAG_PPE42 | POWERPC_FLAG_BUS_CLK;
+}
+
+POWERPC_FAMILY(ppe42)(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
+
+ dc->desc = "PPE 42";
+ pcc->insns_flags2 = PPC2_PPE42;
+ ppe42_class_common_init(pcc);
+}
+
+POWERPC_FAMILY(ppe42x)(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
+
+ dc->desc = "PPE 42X";
+ pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X;
+ ppe42_class_common_init(pcc);
+}
+
+POWERPC_FAMILY(ppe42xm)(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
+
+ dc->desc = "PPE 42XM";
+ pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X | PPC2_PPE42XM;
+ ppe42_class_common_init(pcc);
+}
+
static void init_proc_440EP(CPUPPCState *env)
{
register_BookE_sprs(env, 0x000000000000FFFFULL);
@@ -6802,53 +6941,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 +7016,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 +7397,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)
@@ -7725,6 +7880,18 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
* they can be read with "p $ivor0", "p $ivor1", etc.
*/
break;
+ case POWERPC_EXCP_PPE42:
+ qemu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx "\n",
+ env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
+
+ qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
+ " ISR " TARGET_FMT_lx " EDR " TARGET_FMT_lx "\n",
+ env->spr[SPR_PPE42_TCR], env->spr[SPR_PPE42_TSR],
+ env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
+
+ qemu_fprintf(f, " PIR " TARGET_FMT_lx " IVPR " TARGET_FMT_lx "\n",
+ env->spr[SPR_PPE42_PIR], env->spr[SPR_PPE42_IVPR]);
+ break;
case POWERPC_EXCP_40x:
qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
" ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n",
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 1efdc4066e..d8bca19fff 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -949,6 +949,125 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
powerpc_set_excp_state(cpu, vector, new_msr);
}
+static void powerpc_excp_ppe42(PowerPCCPU *cpu, int excp)
+{
+ CPUPPCState *env = &cpu->env;
+ target_ulong msr, new_msr, vector;
+ target_ulong mcs = PPE42_ISR_MCS_INSTRUCTION;
+ bool promote_unmaskable;
+
+ msr = env->msr;
+
+ /*
+ * New interrupt handler msr preserves SIBRC and ME unless explicitly
+ * overridden by the exception. All other MSR bits are zeroed out.
+ */
+ new_msr = env->msr & (((target_ulong)1 << MSR_ME) | R_MSR_SIBRC_MASK);
+
+ /* HV emu assistance interrupt only exists on server arch 2.05 or later */
+ if (excp == POWERPC_EXCP_HV_EMU) {
+ excp = POWERPC_EXCP_PROGRAM;
+ }
+
+ /*
+ * Unmaskable interrupts (Program, ISI, Alignment and DSI) are promoted to
+ * machine check if MSR_UIE is 0.
+ */
+ promote_unmaskable = !(msr & ((target_ulong)1 << MSR_UIE));
+
+
+ switch (excp) {
+ case POWERPC_EXCP_MCHECK: /* Machine check exception */
+ break;
+ case POWERPC_EXCP_DSI: /* Data storage exception */
+ trace_ppc_excp_dsi(env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
+ if (promote_unmaskable) {
+ excp = POWERPC_EXCP_MCHECK;
+ mcs = PPE42_ISR_MCS_DSI;
+ }
+ break;
+ case POWERPC_EXCP_ISI: /* Instruction storage exception */
+ trace_ppc_excp_isi(msr, env->nip);
+ if (promote_unmaskable) {
+ excp = POWERPC_EXCP_MCHECK;
+ mcs = PPE42_ISR_MCS_ISI;
+ }
+ break;
+ case POWERPC_EXCP_EXTERNAL: /* External input */
+ break;
+ case POWERPC_EXCP_ALIGN: /* Alignment exception */
+ if (promote_unmaskable) {
+ excp = POWERPC_EXCP_MCHECK;
+ mcs = PPE42_ISR_MCS_ALIGNMENT;
+ }
+ break;
+ case POWERPC_EXCP_PROGRAM: /* Program exception */
+ if (promote_unmaskable) {
+ excp = POWERPC_EXCP_MCHECK;
+ mcs = PPE42_ISR_MCS_PROGRAM;
+ }
+ switch (env->error_code & ~0xF) {
+ case POWERPC_EXCP_INVAL:
+ trace_ppc_excp_inval(env->nip);
+ env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_PTR);
+ break;
+ case POWERPC_EXCP_TRAP:
+ env->spr[SPR_PPE42_ISR] |= ((target_ulong)1 << PPE42_ISR_PTR);
+ break;
+ default:
+ /* Should never occur */
+ cpu_abort(env_cpu(env), "Invalid program exception %d. Aborting\n",
+ env->error_code);
+ break;
+ }
+#ifdef CONFIG_TCG
+ env->spr[SPR_PPE42_EDR] = ppc_ldl_code(env, env->nip);
+#endif
+ break;
+ case POWERPC_EXCP_DECR: /* Decrementer exception */
+ break;
+ case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
+ trace_ppc_excp_print("FIT");
+ break;
+ case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
+ trace_ppc_excp_print("WDT");
+ break;
+ case POWERPC_EXCP_RESET: /* System reset exception */
+ /* reset exceptions don't have ME set */
+ new_msr &= ~((target_ulong)1 << MSR_ME);
+ break;
+ default:
+ cpu_abort(env_cpu(env), "Invalid PPE42 exception %d. Aborting\n",
+ excp);
+ break;
+ }
+
+ env->spr[SPR_SRR0] = env->nip;
+ env->spr[SPR_SRR1] = msr;
+
+ vector = env->excp_vectors[excp];
+ if (vector == (target_ulong)-1ULL) {
+ cpu_abort(env_cpu(env),
+ "Raised an exception without defined vector %d\n", excp);
+ }
+ vector |= env->spr[SPR_PPE42_IVPR];
+
+ if (excp == POWERPC_EXCP_MCHECK) {
+ /* Also set the Machine Check Status (MCS) */
+ env->spr[SPR_PPE42_ISR] &= ~R_PPE42_ISR_MCS_MASK;
+ env->spr[SPR_PPE42_ISR] |= (mcs & R_PPE42_ISR_MCS_MASK);
+ env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_MFE);
+
+ /* Machine checks halt execution if MSR_ME is 0 */
+ powerpc_mcheck_checkstop(env);
+
+ /* machine check exceptions don't have ME set */
+ new_msr &= ~((target_ulong)1 << MSR_ME);
+ }
+
+ powerpc_set_excp_state(cpu, vector, new_msr);
+}
+
static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
{
CPUPPCState *env = &cpu->env;
@@ -1589,6 +1708,9 @@ void powerpc_excp(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_POWER11:
powerpc_excp_books(cpu, excp);
break;
+ case POWERPC_EXCP_PPE42:
+ powerpc_excp_ppe42(cpu, excp);
+ break;
default:
g_assert_not_reached();
}
@@ -1945,6 +2067,43 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env,
}
#endif /* TARGET_PPC64 */
+static int ppe42_next_unmasked_interrupt(CPUPPCState *env)
+{
+ bool async_deliver;
+
+ /* External reset */
+ if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+ return PPC_INTERRUPT_RESET;
+ }
+ /* Machine check exception */
+ if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+ return PPC_INTERRUPT_MCK;
+ }
+
+ async_deliver = FIELD_EX64(env->msr, MSR, EE);
+
+ if (async_deliver != 0) {
+ /* Watchdog timer */
+ if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+ return PPC_INTERRUPT_WDT;
+ }
+ /* External Interrupt */
+ if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+ return PPC_INTERRUPT_EXT;
+ }
+ /* Fixed interval timer */
+ if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+ return PPC_INTERRUPT_FIT;
+ }
+ /* Decrementer exception */
+ if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+ return PPC_INTERRUPT_DECR;
+ }
+ }
+
+ return 0;
+}
+
static int ppc_next_unmasked_interrupt(CPUPPCState *env)
{
uint32_t pending_interrupts = env->pending_interrupts;
@@ -1970,6 +2129,10 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
}
#endif
+ if (env->excp_model == POWERPC_EXCP_PPE42) {
+ return ppe42_next_unmasked_interrupt(env);
+ }
+
/* External reset */
if (pending_interrupts & PPC_INTERRUPT_RESET) {
return PPC_INTERRUPT_RESET;
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index 7e5726871e..9953d73884 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -186,6 +186,10 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
if (env->spr[SPR_LPCR] & LPCR_HR) {
hflags |= 1 << HFLAGS_HR;
}
+ if (unlikely(ppc_flags & POWERPC_FLAG_PPE42)) {
+ /* PPE42 has a single address space and no problem state */
+ msr = 0;
+ }
#ifndef CONFIG_USER_ONLY
if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
@@ -306,9 +310,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)) {
@@ -319,8 +320,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 MSR has bits overlapping with others */
+ if (!(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
@@ -462,6 +469,17 @@ void register_generic_sprs(PowerPCCPU *cpu)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+
+ if (env->insns_flags2 & PPC2_PPE42) {
+ spr_register(env, SPR_PVR, "PVR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ pcc->pvr);
+
+ /* PPE42 doesn't support additional SPRG regs or timebase */
+ return;
+ }
+
spr_register(env, SPR_SPRG1, "SPRG1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
diff --git a/target/ppc/tcg-excp_helper.c b/target/ppc/tcg-excp_helper.c
index f835be5156..edecfb8572 100644
--- a/target/ppc/tcg-excp_helper.c
+++ b/target/ppc/tcg-excp_helper.c
@@ -229,6 +229,18 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
case POWERPC_MMU_BOOKE206:
env->spr[SPR_BOOKE_DEAR] = vaddr;
break;
+ case POWERPC_MMU_REAL:
+ if (env->flags & POWERPC_FLAG_PPE42) {
+ env->spr[SPR_PPE42_EDR] = vaddr;
+ if (access_type == MMU_DATA_STORE) {
+ env->spr[SPR_PPE42_ISR] |= PPE42_ISR_ST;
+ } else {
+ env->spr[SPR_PPE42_ISR] &= ~PPE42_ISR_ST;
+ }
+ } else {
+ env->spr[SPR_DAR] = vaddr;
+ }
+ break;
default:
env->spr[SPR_DAR] = vaddr;
break;
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
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 2/4] target/ppc: Add IBM PPE42 special instructions
2025-08-26 20:17 [PATCH v2 0/4] Add IBM PPE42 CPU support Glenn Miles
2025-08-26 20:17 ` [PATCH v2 1/4] target/ppc: Add IBM PPE42 family of processors Glenn Miles
@ 2025-08-26 20:17 ` Glenn Miles
2025-09-04 12:24 ` Chinmay Rath
2025-09-04 12:30 ` Chinmay Rath
2025-08-26 20:17 ` [PATCH v2 3/4] hw/ppc: Add a test machine for the IBM PPE42 CPU Glenn Miles
2025-08-26 20:17 ` [PATCH v2 4/4] tests/functional: Add test for IBM PPE42 instructions Glenn Miles
3 siblings, 2 replies; 14+ messages in thread
From: Glenn Miles @ 2025-08-26 20:17 UTC (permalink / raw)
To: qemu-devel
Cc: Glenn Miles, qemu-ppc, clg, npiggin, harshpb, thuth, rathc,
richard.henderson
Adds the following instructions exclusively for
IBM PPE42 processors:
LSKU
LCXU
STSKU
STCXU
LVD
LVDU
LVDX
STVD
STVDU
STVDX
SLVD
SRVD
CMPWBC
CMPLWBC
CMPWIBC
BNBWI
BNBW
CLRBWIBC
CLRWBC
DCBQ
RLDICL
RLDICR
RLDIMI
A PPE42 GCC compiler is available here:
https://github.com/open-power/ppe42-gcc
For more information on the PPE42 processors please visit:
https://wiki.raptorcs.com/w/images/a/a3/PPE_42X_Core_Users_Manual.pdf
Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
---
target/ppc/insn32.decode | 66 ++-
target/ppc/translate.c | 29 +-
target/ppc/translate/ppe-impl.c.inc | 805 ++++++++++++++++++++++++++++
3 files changed, 890 insertions(+), 10 deletions(-)
create mode 100644 target/ppc/translate/ppe-impl.c.inc
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index e53fd2840d..8beb588a2a 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -58,6 +58,10 @@
%ds_rtp 22:4 !function=times_2
@DS_rtp ...... ....0 ra:5 .............. .. &D rt=%ds_rtp si=%ds_si
+%dd_si 3:s13
+&DD rt ra si:int64_t
+@DD ...... rt:5 ra:5 ............. . .. &DD si=%dd_si
+
&DX_b vrt b
%dx_b 6:10 16:5 0:1
@DX_b ...... vrt:5 ..... .......... ..... . &DX_b b=%dx_b
@@ -66,6 +70,11 @@
%dx_d 6:s10 16:5 0:1
@DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d
+%md_sh 1:1 11:5
+%md_mb 5:1 6:5
+&MD rs ra sh mb rc
+@MD ...... rs:5 ra:5 ..... ...... ... . rc:1 &MD sh=%md_sh mb=%md_mb
+
&VA vrt vra vrb rc
@VA ...... vrt:5 vra:5 vrb:5 rc:5 ...... &VA
@@ -322,6 +331,13 @@ LDUX 011111 ..... ..... ..... 0000110101 - @X
LQ 111000 ..... ..... ............ ---- @DQ_rtp
+LVD 000101 ..... ..... ................ @D
+LVDU 001001 ..... ..... ................ @D
+LVDX 011111 ..... ..... ..... 0000010001 - @X
+LSKU 111010 ..... ..... ............. 0 11 @DD
+LCXU 111010 ..... ..... ............. 1 11 @DD
+
+
### Fixed-Point Store Instructions
STB 100110 ..... ..... ................ @D
@@ -346,6 +362,11 @@ STDUX 011111 ..... ..... ..... 0010110101 - @X
STQ 111110 ..... ..... ..............10 @DS_rtp
+STVDU 010110 ..... ..... ................ @D
+STVDX 011111 ..... ..... ..... 0010010001 - @X
+STSKU 111110 ..... ..... ............. 0 11 @DD
+STCXU 111110 ..... ..... ............. 1 11 @DD
+
### Fixed-Point Compare Instructions
CMP 011111 ... - . ..... ..... 0000000000 - @X_bfl
@@ -461,8 +482,14 @@ PRTYD 011111 ..... ..... ----- 0010111010 - @X_sa
BPERMD 011111 ..... ..... ..... 0011111100 - @X
CFUGED 011111 ..... ..... ..... 0011011100 - @X
-CNTLZDM 011111 ..... ..... ..... 0000111011 - @X
-CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
+{
+ SLVD 011111 ..... ..... ..... 0000111011 . @X_rc
+ CNTLZDM 011111 ..... ..... ..... 0000111011 - @X
+}
+{
+ SRVD 011111 ..... ..... ..... 1000111011 . @X_rc
+ CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
+}
PDEPD 011111 ..... ..... ..... 0010011100 - @X
PEXTD 011111 ..... ..... ..... 0010111100 - @X
@@ -981,8 +1008,16 @@ LXSSP 111001 ..... ..... .............. 11 @DS
STXSSP 111101 ..... ..... .............. 11 @DS
LXV 111101 ..... ..... ............ . 001 @DQ_TSX
STXV 111101 ..... ..... ............ . 101 @DQ_TSX
-LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP
-STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP
+
+# STVD PPE instruction overlaps with the LXVP and STXVP instructions
+{
+ STVD 000110 ..... ..... ................ @D
+ [
+ LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP
+ STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP
+ ]
+}
+
LXVX 011111 ..... ..... ..... 0100 - 01100 . @X_TSX
STXVX 011111 ..... ..... ..... 0110001100 . @X_TSX
LXVPX 011111 ..... ..... ..... 0101001101 - @X_TSXP
@@ -1300,3 +1335,26 @@ CLRBHRB 011111 ----- ----- ----- 0110101110 -
## Misc POWER instructions
ATTN 000000 00000 00000 00000 0100000000 0
+
+# Fused compare-branch instructions for PPE only
+%fcb_bdx 1:s10 !function=times_4
+&FCB px:bool ra rb:uint64_t bdx lk:bool
+@FCB ...... .. px:1 .. ra:5 rb:5 .......... lk:1 &FCB bdx=%fcb_bdx
+&FCB_bix px:bool bix ra rb:uint64_t bdx lk:bool
+@FCB_bix ...... .. px:1 bix:2 ra:5 rb:5 .......... lk:1 &FCB_bix bdx=%fcb_bdx
+
+CMPWBC 000001 00 . .. ..... ..... .......... . @FCB_bix
+CMPLWBC 000001 01 . .. ..... ..... .......... . @FCB_bix
+CMPWIBC 000001 10 . .. ..... ..... .......... . @FCB_bix
+BNBWI 000001 11 . 00 ..... ..... .......... . @FCB
+BNBW 000001 11 . 01 ..... ..... .......... . @FCB
+CLRBWIBC 000001 11 . 10 ..... ..... .......... . @FCB
+CLRBWBC 000001 11 . 11 ..... ..... .......... . @FCB
+
+# Data Cache Block Query for PPE only
+DCBQ 011111 ..... ..... ..... 0110010110 - @X
+
+# Rotate Doubleword Instructions for PPE only (if TARGET_PPC64 not defined)
+RLDICL 011110 ..... ..... ..... ...... 000 . . @MD
+RLDICR 011110 ..... ..... ..... ...... 001 . . @MD
+RLDIMI 011110 ..... ..... ..... ...... 011 . . @MD
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index fc817dab54..d422789a1d 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -209,6 +209,11 @@ struct DisasContext {
#define DISAS_CHAIN DISAS_TARGET_2 /* lookup next tb, pc updated */
#define DISAS_CHAIN_UPDATE DISAS_TARGET_3 /* lookup next tb, pc stale */
+static inline bool is_ppe(const DisasContext *ctx)
+{
+ return !!(ctx->flags & POWERPC_FLAG_PPE42);
+}
+
/* Return true iff byteswap is needed in a scalar memop */
static inline bool need_byteswap(const DisasContext *ctx)
{
@@ -556,11 +561,8 @@ void spr_access_nop(DisasContext *ctx, int sprn, int gprn)
#endif
-/* SPR common to all PowerPC */
-/* XER */
-void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
+static void gen_get_xer(DisasContext *ctx, TCGv dst)
{
- TCGv dst = cpu_gpr[gprn];
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
TCGv t2 = tcg_temp_new();
@@ -579,9 +581,16 @@ void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
}
}
-void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
+/* SPR common to all PowerPC */
+/* XER */
+void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
+{
+ TCGv dst = cpu_gpr[gprn];
+ gen_get_xer(ctx, dst);
+}
+
+static void gen_set_xer(DisasContext *ctx, TCGv src)
{
- TCGv src = cpu_gpr[gprn];
/* Write all flags, while reading back check for isa300 */
tcg_gen_andi_tl(cpu_xer, src,
~((1u << XER_SO) |
@@ -594,6 +603,12 @@ void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1);
}
+void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv src = cpu_gpr[gprn];
+ gen_set_xer(ctx, src);
+}
+
/* LR */
void spr_read_lr(DisasContext *ctx, int gprn, int sprn)
{
@@ -5755,6 +5770,8 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a)
#include "translate/bhrb-impl.c.inc"
+#include "translate/ppe-impl.c.inc"
+
/* Handles lfdp */
static void gen_dform39(DisasContext *ctx)
{
diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ppe-impl.c.inc
new file mode 100644
index 0000000000..98fd794aa4
--- /dev/null
+++ b/target/ppc/translate/ppe-impl.c.inc
@@ -0,0 +1,805 @@
+/*
+ * IBM PPE Instructions
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+
+#if !defined(TARGET_PPC64)
+static bool vdr_is_valid(uint32_t vdr)
+{
+ const uint32_t valid_bitmap = 0xf00003ff;
+ return !!((1ul << (vdr & 0x1f)) & valid_bitmap);
+}
+
+static bool ppe_gpr_is_valid(uint32_t reg)
+{
+ const uint32_t valid_bitmap = 0xf00027ff;
+ return !!((1ul << (reg & 0x1f)) & valid_bitmap);
+}
+#endif
+
+#define CHECK_VDR(CTX, VDR) \
+ do { \
+ if (unlikely(!vdr_is_valid(VDR))) { \
+ gen_invalid(CTX); \
+ return true; \
+ } \
+ } while (0)
+
+#define CHECK_PPE_GPR(CTX, REG) \
+ do { \
+ if (unlikely(!ppe_gpr_is_valid(REG))) { \
+ gen_invalid(CTX); \
+ return true; \
+ } \
+ } while (0)
+
+#define CHECK_VDR(CTX, VDR) \
+ do { \
+ if (unlikely(!vdr_is_valid(VDR))) { \
+ gen_invalid(CTX); \
+ return true; \
+ } \
+ } while (0)
+
+#define VDR_PAIR_REG(VDR) (((VDR) + 1) & 0x1f)
+
+#define CHECK_PPE_LEVEL(CTX, LVL) \
+ do { \
+ if (unlikely(!((CTX)->insns_flags2 & (LVL)))) { \
+ gen_invalid(CTX); \
+ return true; \
+ } \
+ } while (0)
+
+static bool trans_LCXU(DisasContext *ctx, arg_LCXU *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ int i;
+ TCGv base, EA;
+ TCGv lo, hi;
+ TCGv_i64 t8;
+ const uint8_t vd_list[] = {9, 7, 5, 3, 0};
+
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
+ CHECK_PPE_GPR(ctx, a->rt);
+
+ if (unlikely((a->rt != a->ra) || (a->ra == 0) || (a->si < 0xB))) {
+ gen_invalid(ctx);
+ return true;
+ }
+
+ EA = tcg_temp_new();
+ base = tcg_temp_new();
+
+ tcg_gen_addi_tl(base, cpu_gpr[a->ra], a->si * 8);
+ gen_store_spr(SPR_PPE42_EDR, base);
+
+ t8 = tcg_temp_new_i64();
+
+ tcg_gen_addi_tl(EA, base, -8);
+ tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+ tcg_gen_extr_i64_tl(cpu_gpr[31], cpu_gpr[30], t8);
+
+ tcg_gen_addi_tl(EA, EA, -8);
+ tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+ tcg_gen_extr_i64_tl(cpu_gpr[29], cpu_gpr[28], t8);
+
+ lo = tcg_temp_new();
+ hi = tcg_temp_new();
+
+ tcg_gen_addi_tl(EA, EA, -8);
+ tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+ tcg_gen_extr_i64_tl(lo, hi, t8);
+ gen_store_spr(SPR_SRR0, hi);
+ gen_store_spr(SPR_SRR1, lo);
+
+ tcg_gen_addi_tl(EA, EA, -8);
+ tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+ tcg_gen_extr_i64_tl(lo, hi, t8);
+ gen_set_xer(ctx, hi);
+ tcg_gen_mov_tl(cpu_ctr, lo);
+
+ for (i = 0; i < sizeof(vd_list); i++) {
+ int vd = vd_list[i];
+ tcg_gen_addi_tl(EA, EA, -8);
+ tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+ tcg_gen_extr_i64_tl(cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd], t8);
+ }
+
+ tcg_gen_addi_tl(EA, EA, -8);
+ tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+ tcg_gen_extr_i64_tl(lo, hi, t8);
+ tcg_gen_shri_tl(hi, hi, 28);
+ tcg_gen_trunc_tl_i32(cpu_crf[0], hi);
+ gen_store_spr(SPR_SPRG0, lo);
+
+ tcg_gen_addi_tl(EA, base, 4);
+ tcg_gen_qemu_ld_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
+ tcg_gen_mov_tl(cpu_gpr[a->ra], base);
+ return true;
+#endif
+}
+
+static bool trans_LSKU(DisasContext *ctx, arg_LSKU *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ int64_t n;
+ TCGv base, EA;
+ TCGv_i32 lo, hi;
+ TCGv_i64 t8;
+
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+
+ CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
+ CHECK_PPE_GPR(ctx, a->rt);
+
+ if (unlikely((a->rt != a->ra) || (a->ra == 0) ||
+ (a->si & PPC_BIT(0)) || (a->si == 0))) {
+ gen_invalid(ctx);
+ return true;
+ }
+
+ EA = tcg_temp_new();
+ base = tcg_temp_new();
+ gen_addr_register(ctx, base);
+
+
+ tcg_gen_addi_tl(base, base, a->si * 8);
+ gen_store_spr(SPR_PPE42_EDR, base);
+
+ n = a->si - 1;
+ t8 = tcg_temp_new_i64();
+ if (n > 0) {
+ tcg_gen_addi_tl(EA, base, -8);
+ tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+ hi = cpu_gpr[30];
+ lo = cpu_gpr[31];
+ tcg_gen_extr_i64_i32(lo, hi, t8);
+ }
+ if (n > 1) {
+ tcg_gen_addi_tl(EA, base, -16);
+ tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+ hi = cpu_gpr[28];
+ lo = cpu_gpr[29];
+ tcg_gen_extr_i64_i32(lo, hi, t8);
+ }
+ tcg_gen_addi_tl(EA, base, 4);
+ tcg_gen_qemu_ld_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
+ tcg_gen_mov_tl(cpu_gpr[a->ra], base);
+ return true;
+#endif
+}
+
+static bool trans_STCXU(DisasContext *ctx, arg_STCXU *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ TCGv EA;
+ TCGv lo, hi;
+ TCGv_i64 t8;
+ int i;
+ const uint8_t vd_list[] = {9, 7, 5, 3, 0};
+
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+
+ CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
+ CHECK_PPE_GPR(ctx, a->rt);
+
+ if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) {
+ gen_invalid(ctx);
+ return true;
+ }
+
+ EA = tcg_temp_new();
+ tcg_gen_addi_tl(EA, cpu_gpr[a->ra], 4);
+ tcg_gen_qemu_st_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
+
+ gen_store_spr(SPR_PPE42_EDR, cpu_gpr[a->ra]);
+
+ t8 = tcg_temp_new_i64();
+
+ tcg_gen_concat_tl_i64(t8, cpu_gpr[31], cpu_gpr[30]);
+ tcg_gen_addi_tl(EA, cpu_gpr[a->ra], -8);
+ tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+
+ tcg_gen_concat_tl_i64(t8, cpu_gpr[29], cpu_gpr[28]);
+ tcg_gen_addi_tl(EA, EA, -8);
+ tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+
+ lo = tcg_temp_new();
+ hi = tcg_temp_new();
+
+ gen_load_spr(hi, SPR_SRR0);
+ gen_load_spr(lo, SPR_SRR1);
+ tcg_gen_concat_tl_i64(t8, lo, hi);
+ tcg_gen_addi_tl(EA, EA, -8);
+ tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+
+ gen_get_xer(ctx, hi);
+ tcg_gen_mov_tl(lo, cpu_ctr);
+ tcg_gen_concat_tl_i64(t8, lo, hi);
+ tcg_gen_addi_tl(EA, EA, -8);
+ tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+
+ for (i = 0; i < sizeof(vd_list); i++) {
+ int vd = vd_list[i];
+ tcg_gen_concat_tl_i64(t8, cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd]);
+ tcg_gen_addi_tl(EA, EA, -8);
+ tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+ }
+
+ gen_load_spr(lo, SPR_SPRG0);
+ tcg_gen_extu_i32_tl(hi, cpu_crf[0]);
+ tcg_gen_shli_tl(hi, hi, 28);
+ tcg_gen_concat_tl_i64(t8, lo, hi);
+ tcg_gen_addi_tl(EA, EA, -8);
+ tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+
+ tcg_gen_addi_tl(EA, cpu_gpr[a->ra], a->si * 8);
+ tcg_gen_qemu_st_i32(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) |
+ MO_ALIGN);
+ tcg_gen_mov_tl(cpu_gpr[a->ra], EA);
+ return true;
+#endif
+}
+
+static bool trans_STSKU(DisasContext *ctx, arg_STSKU *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ int64_t n;
+ TCGv base, EA;
+ TCGv_i32 lo, hi;
+ TCGv_i64 t8;
+
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+
+ CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
+ CHECK_PPE_GPR(ctx, a->rt);
+
+ if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) {
+ gen_invalid(ctx);
+ return true;
+ }
+
+ EA = tcg_temp_new();
+ base = tcg_temp_new();
+ gen_addr_register(ctx, base);
+ tcg_gen_addi_tl(EA, base, 4);
+ tcg_gen_qemu_st_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
+
+ gen_store_spr(SPR_PPE42_EDR, base);
+
+ n = ~(a->si);
+
+ t8 = tcg_temp_new_i64();
+ if (n > 0) {
+ hi = cpu_gpr[30];
+ lo = cpu_gpr[31];
+ tcg_gen_concat_i32_i64(t8, lo, hi);
+ tcg_gen_addi_tl(EA, base, -8);
+ tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+ }
+ if (n > 1) {
+ hi = cpu_gpr[28];
+ lo = cpu_gpr[29];
+ tcg_gen_concat_i32_i64(t8, lo, hi);
+ tcg_gen_addi_tl(EA, base, -16);
+ tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
+ }
+
+ tcg_gen_addi_tl(EA, base, a->si * 8);
+ tcg_gen_qemu_st_i32(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) |
+ MO_ALIGN);
+ tcg_gen_mov_tl(cpu_gpr[a->ra], EA);
+ return true;
+#endif
+}
+
+#if !defined(TARGET_PPC64)
+static bool do_ppe_ldst(DisasContext *ctx, int rt, int ra, TCGv displ,
+ bool update, bool store)
+{
+ TCGv ea;
+ int rt_lo;
+ TCGv_i64 t8;
+
+ CHECK_VDR(ctx, rt);
+ CHECK_PPE_GPR(ctx, ra);
+ rt_lo = VDR_PAIR_REG(rt);
+ if (update && (ra == 0 || (!store && ((ra == rt) || (ra == rt_lo))))) {
+ gen_invalid(ctx);
+ return true;
+ }
+ gen_set_access_type(ctx, ACCESS_INT);
+
+ ea = do_ea_calc(ctx, ra, displ);
+ t8 = tcg_temp_new_i64();
+ if (store) {
+ tcg_gen_concat_i32_i64(t8, cpu_gpr[rt_lo], cpu_gpr[rt]);
+ tcg_gen_qemu_st_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64));
+ } else {
+ tcg_gen_qemu_ld_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64));
+ tcg_gen_extr_i64_i32(cpu_gpr[rt_lo], cpu_gpr[rt], t8);
+ }
+ if (update) {
+ tcg_gen_mov_tl(cpu_gpr[ra], ea);
+ }
+ return true;
+}
+#endif
+
+static bool trans_LVD(DisasContext *ctx, arg_LVD *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), false, false);
+#endif
+}
+
+static bool trans_LVDU(DisasContext *ctx, arg_LVDU *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), true, false);
+#endif
+}
+
+static bool trans_LVDX(DisasContext *ctx, arg_LVDX *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_GPR(ctx, a->rb);
+ return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, false);
+#endif
+}
+
+static bool trans_STVD(DisasContext *ctx, arg_STVD *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), false, true);
+#endif
+}
+
+static bool trans_STVDU(DisasContext *ctx, arg_STVDU *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), true, true);
+#endif
+}
+
+static bool trans_STVDX(DisasContext *ctx, arg_STVDX *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_GPR(ctx, a->rb);
+ return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, true);
+#endif
+}
+
+#if !defined(TARGET_PPC64)
+static bool do_fcb(DisasContext *ctx, TCGv ra_val, TCGv rb_val, int bix,
+ int32_t bdx, bool s, bool px, bool lk)
+{
+ TCGCond cond;
+ uint32_t mask;
+ TCGLabel *no_branch;
+ target_ulong dest;
+
+ /* Update CR0 */
+ gen_op_cmp32(ra_val, rb_val, s, 0);
+
+ if (lk) {
+ gen_setlr(ctx, ctx->base.pc_next);
+ }
+
+
+ mask = PPC_BIT32(28 + bix);
+ cond = (px) ? TCG_COND_TSTEQ : TCG_COND_TSTNE;
+ no_branch = gen_new_label();
+ dest = ctx->cia + bdx;
+
+ /* Do the branch if CR0[bix] == PX */
+ tcg_gen_brcondi_i32(cond, cpu_crf[0], mask, no_branch);
+ gen_goto_tb(ctx, 0, dest);
+ gen_set_label(no_branch);
+ gen_goto_tb(ctx, 1, ctx->base.pc_next);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+#endif
+
+#if !defined(TARGET_PPC64)
+static bool do_cmp_branch(DisasContext *ctx, int ra, TCGv rb_val, int bix,
+ int32_t bdx, bool s, bool px, bool lk)
+{
+ TCGv old_ra;
+
+ CHECK_PPE_GPR(ctx, ra);
+ if (bix == 3) {
+ old_ra = tcg_temp_new();
+ tcg_gen_mov_tl(old_ra, cpu_gpr[ra]);
+ tcg_gen_sub_tl(cpu_gpr[ra], cpu_gpr[ra], rb_val);
+ return do_fcb(ctx, old_ra, rb_val, 2,
+ bdx, s, px, lk);
+ } else {
+ return do_fcb(ctx, cpu_gpr[ra], rb_val, bix,
+ bdx, s, px, lk);
+ }
+}
+#endif
+
+#if !defined(TARGET_PPC64)
+static bool do_mask_branch(DisasContext *ctx, int ra, TCGv mask,
+ int32_t bdx, bool invert, bool px, bool lk,
+ bool update)
+{
+ TCGv r;
+ CHECK_PPE_GPR(ctx, ra);
+ if (invert) {
+ tcg_gen_not_tl(mask, mask);
+ }
+
+ /* apply mask to ra */
+ r = tcg_temp_new();
+ tcg_gen_and_tl(r, cpu_gpr[ra], mask);
+ if (update) {
+ tcg_gen_mov_tl(cpu_gpr[ra], r);
+ }
+ return do_fcb(ctx, r, tcg_constant_tl(0), 2,
+ bdx, false, px, lk);
+}
+#endif
+
+static bool trans_CMPWBC(DisasContext *ctx, arg_CMPWBC *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_GPR(ctx, a->rb);
+ return do_cmp_branch(ctx, a->ra, cpu_gpr[a->rb], a->bix, a->bdx,
+ true, a->px, a->lk);
+#endif
+}
+
+static bool trans_CMPLWBC(DisasContext *ctx, arg_CMPLWBC *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_GPR(ctx, a->rb);
+ return do_cmp_branch(ctx, a->ra, cpu_gpr[a->rb], a->bix, a->bdx,
+ false, a->px, a->lk);
+#endif
+}
+
+static bool trans_CMPWIBC(DisasContext *ctx, arg_CMPWIBC *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ return do_cmp_branch(ctx, a->ra, tcg_constant_tl(a->rb), a->bix, a->bdx,
+ true, a->px, a->lk);
+#endif
+}
+
+static bool trans_BNBWI(DisasContext *ctx, arg_BNBWI *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ return do_mask_branch(ctx, a->ra, tcg_constant_tl(PPC_BIT32(a->rb)),
+ a->bdx, false, a->px, a->lk, false);
+#endif
+}
+
+static bool trans_BNBW(DisasContext *ctx, arg_BNBW *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ TCGv mask, shift;
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_GPR(ctx, a->rb);
+ mask = tcg_temp_new();
+ shift = tcg_temp_new();
+ tcg_gen_andi_tl(shift, cpu_gpr[a->rb], 0x1f);
+ tcg_gen_shr_tl(mask, tcg_constant_tl(0x80000000), shift);
+ return do_mask_branch(ctx, a->ra, mask, a->bdx, false, a->px, a->lk, false);
+#endif
+}
+
+static bool trans_CLRBWIBC(DisasContext *ctx, arg_CLRBWIBC *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ return do_mask_branch(ctx, a->ra, tcg_constant_tl(PPC_BIT32(a->rb)),
+ a->bdx, true, a->px, a->lk, true);
+#endif
+}
+
+static bool trans_CLRBWBC(DisasContext *ctx, arg_CLRBWBC *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ TCGv mask, shift;
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_GPR(ctx, a->rb);
+ mask = tcg_temp_new();
+ shift = tcg_temp_new();
+ tcg_gen_andi_tl(shift, cpu_gpr[a->rb], 0x1f);
+ tcg_gen_shr_tl(mask, tcg_constant_tl(0x80000000), shift);
+ return do_mask_branch(ctx, a->ra, mask, a->bdx, true, a->px, a->lk, true);
+#endif
+}
+
+#if !defined(TARGET_PPC64)
+static void gen_set_Rc0_i64(DisasContext *ctx, TCGv_i64 reg)
+{
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i32 t = tcg_temp_new_i32();
+
+ tcg_gen_movi_i64(t0, CRF_EQ);
+ tcg_gen_movi_i64(t1, CRF_LT);
+ tcg_gen_movcond_i64(TCG_COND_LT, t0, reg, tcg_constant_i64(0), t1, t0);
+ tcg_gen_movi_i64(t1, CRF_GT);
+ tcg_gen_movcond_i64(TCG_COND_GT, t0, reg, tcg_constant_i64(0), t1, t0);
+ tcg_gen_extrl_i64_i32(t, t0);
+ tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
+ tcg_gen_or_i32(cpu_crf[0], cpu_crf[0], t);
+}
+#endif
+
+#if !defined(TARGET_PPC64)
+static bool do_shift64(DisasContext *ctx, arg_X_rc *a, bool left)
+{
+ int rt_lo, ra_lo;
+ TCGv_i64 t0, t8;
+
+ /* Check for PPE since opcode overlaps with CNTTZDM instruction */
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
+ CHECK_VDR(ctx, a->rt);
+ CHECK_VDR(ctx, a->ra);
+ CHECK_PPE_GPR(ctx, a->rb);
+ rt_lo = VDR_PAIR_REG(a->rt);
+ ra_lo = VDR_PAIR_REG(a->ra);
+ t8 = tcg_temp_new_i64();
+
+ /* AND rt with a mask that is 0 when rb >= 0x40 */
+ t0 = tcg_temp_new_i64();
+ tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]);
+ tcg_gen_shli_i64(t0, t0, 0x39);
+ tcg_gen_sari_i64(t0, t0, 0x3f);
+
+ /* form 64bit value from two 32bit regs */
+ tcg_gen_concat_tl_i64(t8, cpu_gpr[rt_lo], cpu_gpr[a->rt]);
+
+ /* apply mask */
+ tcg_gen_andc_i64(t8, t8, t0);
+
+ /* do the shift */
+ tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]);
+ tcg_gen_andi_i64(t0, t0, 0x3f);
+ if (left) {
+ tcg_gen_shl_i64(t8, t8, t0);
+ } else {
+ tcg_gen_shr_i64(t8, t8, t0);
+ }
+
+ /* split the 64bit word back into two 32bit regs */
+ tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8);
+
+ /* update CR0 if requested */
+ if (unlikely(a->rc != 0)) {
+ gen_set_Rc0_i64(ctx, t8);
+ }
+ return true;
+}
+#endif
+
+static bool trans_SRVD(DisasContext *ctx, arg_SRVD *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ return do_shift64(ctx, a, false);
+#endif
+}
+
+static bool trans_SLVD(DisasContext *ctx, arg_SLVD *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ return do_shift64(ctx, a, true);
+#endif
+}
+
+static bool trans_DCBQ(DisasContext *ctx, arg_DCBQ *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+
+ CHECK_PPE_GPR(ctx, a->rt);
+ CHECK_PPE_GPR(ctx, a->ra);
+ CHECK_PPE_GPR(ctx, a->rb);
+
+ /* No cache exists, so just set RT to 0 */
+ tcg_gen_movi_tl(cpu_gpr[a->rt], 0);
+ return true;
+#endif
+}
+
+static bool trans_RLDIMI(DisasContext *ctx, arg_RLDIMI *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ TCGv_i64 t_rs, t_ra;
+ int ra_lo, rs_lo;
+ uint32_t sh = a->sh;
+ uint32_t mb = a->mb;
+ uint32_t me = 63 - sh;
+
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
+ CHECK_VDR(ctx, a->rs);
+ CHECK_VDR(ctx, a->ra);
+
+ rs_lo = VDR_PAIR_REG(a->rs);
+ ra_lo = VDR_PAIR_REG(a->ra);
+
+ t_rs = tcg_temp_new_i64();
+ t_ra = tcg_temp_new_i64();
+
+ tcg_gen_concat_tl_i64(t_rs, cpu_gpr[rs_lo], cpu_gpr[a->rs]);
+ tcg_gen_concat_tl_i64(t_ra, cpu_gpr[ra_lo], cpu_gpr[a->ra]);
+
+ if (mb <= me) {
+ tcg_gen_deposit_i64(t_ra, t_ra, t_rs, sh, me - mb + 1);
+ } else {
+ uint64_t mask = mask_u64(mb, me);
+ TCGv_i64 t1 = tcg_temp_new_i64();
+
+ tcg_gen_rotli_i64(t1, t_rs, sh);
+ tcg_gen_andi_i64(t1, t1, mask);
+ tcg_gen_andi_i64(t_ra, t_ra, ~mask);
+ tcg_gen_or_i64(t_ra, t_ra, t1);
+ }
+
+ tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t_ra);
+
+ if (unlikely(a->rc != 0)) {
+ gen_set_Rc0_i64(ctx, t_ra);
+ }
+ return true;
+#endif
+}
+
+
+#if !defined(TARGET_PPC64)
+static bool gen_rldinm_i64(DisasContext *ctx, arg_MD *a, int mb, int me, int sh)
+{
+ int len = me - mb + 1;
+ int rsh = (64 - sh) & 63;
+ int ra_lo, rs_lo;
+ TCGv_i64 t8;
+
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
+ CHECK_VDR(ctx, a->rs);
+ CHECK_VDR(ctx, a->ra);
+
+ rs_lo = VDR_PAIR_REG(a->rs);
+ ra_lo = VDR_PAIR_REG(a->ra);
+ t8 = tcg_temp_new_i64();
+ tcg_gen_concat_tl_i64(t8, cpu_gpr[rs_lo], cpu_gpr[a->rs]);
+ if (sh != 0 && len > 0 && me == (63 - sh)) {
+ tcg_gen_deposit_z_i64(t8, t8, sh, len);
+ } else if (me == 63 && rsh + len <= 64) {
+ tcg_gen_extract_i64(t8, t8, rsh, len);
+ } else {
+ tcg_gen_rotli_i64(t8, t8, sh);
+ tcg_gen_andi_i64(t8, t8, mask_u64(mb, me));
+ }
+ tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8);
+ if (unlikely(a->rc != 0)) {
+ gen_set_Rc0_i64(ctx, t8);
+ }
+ return true;
+}
+#endif
+
+static bool trans_RLDICL(DisasContext *ctx, arg_RLDICL *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ return gen_rldinm_i64(ctx, a, a->mb, 63, a->sh);
+#endif
+}
+
+static bool trans_RLDICR(DisasContext *ctx, arg_RLDICR *a)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ return gen_rldinm_i64(ctx, a, 0, a->mb, a->sh);
+#endif
+}
+
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 3/4] hw/ppc: Add a test machine for the IBM PPE42 CPU
2025-08-26 20:17 [PATCH v2 0/4] Add IBM PPE42 CPU support Glenn Miles
2025-08-26 20:17 ` [PATCH v2 1/4] target/ppc: Add IBM PPE42 family of processors Glenn Miles
2025-08-26 20:17 ` [PATCH v2 2/4] target/ppc: Add IBM PPE42 special instructions Glenn Miles
@ 2025-08-26 20:17 ` Glenn Miles
2025-09-01 7:25 ` Cédric Le Goater
2025-08-26 20:17 ` [PATCH v2 4/4] tests/functional: Add test for IBM PPE42 instructions Glenn Miles
3 siblings, 1 reply; 14+ messages in thread
From: Glenn Miles @ 2025-08-26 20:17 UTC (permalink / raw)
To: qemu-devel
Cc: Glenn Miles, qemu-ppc, clg, npiggin, harshpb, thuth, rathc,
richard.henderson
Adds a test machine for the IBM PPE42 processor, including a
DEC, FIT, WDT and 1MB of ram.
The purpose of this machine is only to provide a generic platform
for testing instructions of the recently added PPE42 processor
model which is used extensively in the IBM Power9, Power10 and
future Power server processors.
Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
---
Changes from previous version
- Added ppe42_machine.c to MAINTAINERS file with self as maintainer
MAINTAINERS | 6 ++++
hw/ppc/Kconfig | 9 ++++++
hw/ppc/meson.build | 2 ++
hw/ppc/ppc_booke.c | 7 ++++-
hw/ppc/ppe42_machine.c | 69 ++++++++++++++++++++++++++++++++++++++++++
include/hw/ppc/ppc.h | 1 +
6 files changed, 93 insertions(+), 1 deletion(-)
create mode 100644 hw/ppc/ppe42_machine.c
diff --git a/MAINTAINERS b/MAINTAINERS
index a07086ed76..52fa303e0a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1531,6 +1531,12 @@ F: include/hw/pci-host/grackle.h
F: pc-bios/qemu_vga.ndrv
F: tests/functional/test_ppc_mac.py
+PPE42
+M: Glenn Miles <milesg@linux.ibm.com>
+L: qemu-ppc@nongnu.org
+S: Odd Fixes
+F: hw/ppc/ppe42_machine.c
+
PReP
M: Hervé Poussineau <hpoussin@reactos.org>
L: qemu-ppc@nongnu.org
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index ced6bbc740..3fdea5919c 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -44,6 +44,15 @@ config POWERNV
select SSI_M25P80
select PNV_SPI
+config PPC405
+ bool
+ default y
+ depends on PPC
+ select M48T59
+ select PFLASH_CFI02
+ select PPC4XX
+ select SERIAL
+
config PPC440
bool
default y
diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
index 9893f8adeb..170b90ae7d 100644
--- a/hw/ppc/meson.build
+++ b/hw/ppc/meson.build
@@ -57,6 +57,8 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
'pnv_n1_chiplet.c',
))
# PowerPC 4xx boards
+ppc_ss.add(when: 'CONFIG_PPC405', if_true: files(
+ 'ppe42_machine.c'))
ppc_ss.add(when: 'CONFIG_PPC440', if_true: files(
'ppc440_bamboo.c',
'ppc440_uc.c'))
diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c
index 3872ae2822..13403a56b1 100644
--- a/hw/ppc/ppc_booke.c
+++ b/hw/ppc/ppc_booke.c
@@ -352,7 +352,12 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
booke_timer = g_new0(booke_timer_t, 1);
cpu->env.tb_env = tb_env;
- tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
+ if (flags & PPC_TIMER_PPE) {
+ /* PPE's use a modified version of the booke behavior */
+ tb_env->flags = flags | PPC_DECR_UNDERFLOW_TRIGGERED;
+ } else {
+ tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
+ }
tb_env->tb_freq = freq;
tb_env->decr_freq = freq;
diff --git a/hw/ppc/ppe42_machine.c b/hw/ppc/ppe42_machine.c
new file mode 100644
index 0000000000..0bc295da28
--- /dev/null
+++ b/hw/ppc/ppe42_machine.c
@@ -0,0 +1,69 @@
+
+/*
+ * Test Machine for the IBM PPE42 processor
+ *
+ * Copyright (c) 2025, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/error-report.h"
+#include "system/address-spaces.h"
+#include "hw/boards.h"
+#include "hw/ppc/ppc.h"
+#include "system/system.h"
+#include "system/reset.h"
+#include "system/kvm.h"
+
+static void main_cpu_reset(void *opaque)
+{
+ PowerPCCPU *cpu = opaque;
+
+ cpu_reset(CPU(cpu));
+}
+
+static void ppe42_machine_init(MachineState *machine)
+{
+ PowerPCCPU *cpu;
+ CPUPPCState *env;
+
+ if (kvm_enabled()) {
+ error_report("machine %s does not support the KVM accelerator",
+ MACHINE_GET_CLASS(machine)->name);
+ exit(EXIT_FAILURE);
+ }
+
+ /* init CPU */
+ cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
+ env = &cpu->env;
+ if (PPC_INPUT(env) != PPC_FLAGS_INPUT_PPE42) {
+ error_report("Incompatible CPU, only PPE42 bus supported");
+ exit(1);
+ }
+
+ qemu_register_reset(main_cpu_reset, cpu);
+
+ /* This sets the decrementer timebase */
+ ppc_booke_timers_init(cpu, 37500000, PPC_TIMER_PPE);
+
+ /* RAM */
+ if (machine->ram_size > 2 * GiB) {
+ error_report("RAM size more than 2 GiB is not supported");
+ exit(1);
+ }
+ memory_region_add_subregion(get_system_memory(), 0xfff80000, machine->ram);
+}
+
+
+static void ppe42_machine_class_init(MachineClass *mc)
+{
+ mc->desc = "PPE42 Test Machine";
+ mc->init = ppe42_machine_init;
+ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("PPE42XM");
+ mc->default_ram_id = "ram";
+ mc->default_ram_size = 1 * MiB;
+}
+
+DEFINE_MACHINE("ppe42_machine", ppe42_machine_class_init)
diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h
index 8a14d623f8..cb51d704c6 100644
--- a/include/hw/ppc/ppc.h
+++ b/include/hw/ppc/ppc.h
@@ -52,6 +52,7 @@ struct ppc_tb_t {
#define PPC_DECR_UNDERFLOW_LEVEL (1 << 4) /* Decr interrupt active when
* the most significant bit is 1.
*/
+#define PPC_TIMER_PPE (1 << 5) /* Enable PPE support */
uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq);
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 4/4] tests/functional: Add test for IBM PPE42 instructions
2025-08-26 20:17 [PATCH v2 0/4] Add IBM PPE42 CPU support Glenn Miles
` (2 preceding siblings ...)
2025-08-26 20:17 ` [PATCH v2 3/4] hw/ppc: Add a test machine for the IBM PPE42 CPU Glenn Miles
@ 2025-08-26 20:17 ` Glenn Miles
3 siblings, 0 replies; 14+ messages in thread
From: Glenn Miles @ 2025-08-26 20:17 UTC (permalink / raw)
To: qemu-devel
Cc: Glenn Miles, qemu-ppc, clg, npiggin, harshpb, thuth, rathc,
richard.henderson
Adds a functional test for the IBM PPE42 instructions which
downloads a test image from a public github repo and then
loads and executes the image.
(see https://github.com/milesg-github/ppe42-tests for details)
Test status is checked by periodically issuing 'info register'
commands and checking the NIP value. If the NIP is 0xFFF80200
then the test successfully executed to completion. If the
machine stops before the test completes or if a 90 second
timeout is reached, then the test is marked as having failed.
This test does not test any PowerPC instructions as it is
expected that these instructions are well covered in other
tests. Only instructions that are unique to the IBM PPE42
processor are tested.
Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
Changes from previous version
- Added test_ppc_ppe42.py file to MAINTAINERS file
MAINTAINERS | 1 +
tests/functional/meson.build | 1 +
tests/functional/test_ppc_ppe42.py | 79 ++++++++++++++++++++++++++++++
3 files changed, 81 insertions(+)
create mode 100644 tests/functional/test_ppc_ppe42.py
diff --git a/MAINTAINERS b/MAINTAINERS
index 52fa303e0a..af412ad0ce 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1536,6 +1536,7 @@ M: Glenn Miles <milesg@linux.ibm.com>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/ppe42_machine.c
+F: tests/functional/test_ppc_ppe42.py
PReP
M: Hervé Poussineau <hpoussin@reactos.org>
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index 311c6f1806..ddfef55bd2 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -233,6 +233,7 @@ tests_ppc_system_quick = [
]
tests_ppc_system_thorough = [
+ 'ppc_ppe42',
'ppc_40p',
'ppc_amiga',
'ppc_bamboo',
diff --git a/tests/functional/test_ppc_ppe42.py b/tests/functional/test_ppc_ppe42.py
new file mode 100644
index 0000000000..26bbe11b2d
--- /dev/null
+++ b/tests/functional/test_ppc_ppe42.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+#
+# Functional tests for the IBM PPE42 processor
+#
+# Copyright (c) 2025, IBM Corporation
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import QemuSystemTest, Asset
+import asyncio
+
+class Ppe42Machine(QemuSystemTest):
+
+ timeout = 90
+ poll_period = 1.0
+
+ ASSET_PPE42_TEST_IMAGE = Asset(
+ ('https://github.com/milesg-github/ppe42-tests/raw/refs/heads/main/'
+ 'images/ppe42-test.out'),
+ '03c1ac0fb7f6c025102a02776a93b35101dae7c14b75e4eab36a337e39042ea8')
+
+ def _test_completed(self):
+ self.log.info("Checking for test completion...")
+ try:
+ output = self.vm.cmd('human-monitor-command',
+ command_line='info registers')
+ except Exception as err:
+ self.log.debug(f"'info registers' cmd failed due to {err=},"
+ " {type(err)=}")
+ raise
+
+ self.log.info(output)
+ if "NIP fff80200" in output:
+ self.log.info("<test completed>")
+ return True
+ else:
+ self.log.info("<test not completed>")
+ return False
+
+ def _wait_pass_fail(self, timeout):
+ while not self._test_completed():
+ if timeout >= self.poll_period:
+ timeout = timeout - self.poll_period
+ self.log.info(f"Waiting {self.poll_period} seconds for test"
+ " to complete...")
+ e = None
+ try:
+ e = self.vm.event_wait('STOP', self.poll_period)
+
+ except asyncio.TimeoutError:
+ self.log.info("Poll period ended.")
+ pass
+
+ except Exception as err:
+ self.log.debug(f"event_wait() failed due to {err=},"
+ " {type(err)=}")
+ raise
+
+ if e != None:
+ self.log.debug(f"Execution stopped: {e}")
+ self.log.debug("Exiting due to test failure")
+ self.fail("Failure detected!")
+ break
+ else:
+ self.fail("Timed out waiting for test completion.")
+
+ def test_ppe42_instructions(self):
+ self.set_machine('ppe42_machine')
+ self.require_accelerator("tcg")
+ image_path = self.ASSET_PPE42_TEST_IMAGE.fetch()
+ self.vm.add_args('-nographic')
+ self.vm.add_args('-device', f'loader,file={image_path}')
+ self.vm.add_args('-device', 'loader,addr=0xfff80040,cpu-num=0')
+ self.vm.add_args('-action', 'panic=pause')
+ self.vm.launch()
+ self._wait_pass_fail(self.timeout)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 3/4] hw/ppc: Add a test machine for the IBM PPE42 CPU
2025-08-26 20:17 ` [PATCH v2 3/4] hw/ppc: Add a test machine for the IBM PPE42 CPU Glenn Miles
@ 2025-09-01 7:25 ` Cédric Le Goater
2025-09-01 10:15 ` BALATON Zoltan
2025-09-02 16:56 ` Miles Glenn
0 siblings, 2 replies; 14+ messages in thread
From: Cédric Le Goater @ 2025-09-01 7:25 UTC (permalink / raw)
To: Glenn Miles, qemu-devel
Cc: qemu-ppc, npiggin, harshpb, thuth, rathc, richard.henderson
On 8/26/25 22:17, Glenn Miles wrote:
> Adds a test machine for the IBM PPE42 processor, including a
> DEC, FIT, WDT and 1MB of ram.
>
> The purpose of this machine is only to provide a generic platform
> for testing instructions of the recently added PPE42 processor
> model which is used extensively in the IBM Power9, Power10 and
> future Power server processors.
>
> Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
> ---
>
> Changes from previous version
> - Added ppe42_machine.c to MAINTAINERS file with self as maintainer
>
> MAINTAINERS | 6 ++++
> hw/ppc/Kconfig | 9 ++++++
> hw/ppc/meson.build | 2 ++
> hw/ppc/ppc_booke.c | 7 ++++-
> hw/ppc/ppe42_machine.c | 69 ++++++++++++++++++++++++++++++++++++++++++
> include/hw/ppc/ppc.h | 1 +
> 6 files changed, 93 insertions(+), 1 deletion(-)
> create mode 100644 hw/ppc/ppe42_machine.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a07086ed76..52fa303e0a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1531,6 +1531,12 @@ F: include/hw/pci-host/grackle.h
> F: pc-bios/qemu_vga.ndrv
> F: tests/functional/test_ppc_mac.py
>
> +PPE42
> +M: Glenn Miles <milesg@linux.ibm.com>
> +L: qemu-ppc@nongnu.org
> +S: Odd Fixes
> +F: hw/ppc/ppe42_machine.c
> +
> PReP
> M: Hervé Poussineau <hpoussin@reactos.org>
> L: qemu-ppc@nongnu.org
> diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
> index ced6bbc740..3fdea5919c 100644
> --- a/hw/ppc/Kconfig
> +++ b/hw/ppc/Kconfig
> @@ -44,6 +44,15 @@ config POWERNV
> select SSI_M25P80
> select PNV_SPI
>
> +config PPC405
> + bool
> + default y
> + depends on PPC
> + select M48T59
> + select PFLASH_CFI02
> + select PPC4XX
> + select SERIAL
> +
> config PPC440
> bool
> default y
> diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
> index 9893f8adeb..170b90ae7d 100644
> --- a/hw/ppc/meson.build
> +++ b/hw/ppc/meson.build
> @@ -57,6 +57,8 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
> 'pnv_n1_chiplet.c',
> ))
> # PowerPC 4xx boards
> +ppc_ss.add(when: 'CONFIG_PPC405', if_true: files(
> + 'ppe42_machine.c'))
> ppc_ss.add(when: 'CONFIG_PPC440', if_true: files(
> 'ppc440_bamboo.c',
> 'ppc440_uc.c'))
> diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c
> index 3872ae2822..13403a56b1 100644
> --- a/hw/ppc/ppc_booke.c
> +++ b/hw/ppc/ppc_booke.c
> @@ -352,7 +352,12 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
> booke_timer = g_new0(booke_timer_t, 1);
>
> cpu->env.tb_env = tb_env;
> - tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
> + if (flags & PPC_TIMER_PPE) {
PPC_TIMER_PPE definition should be introduced in its own patch.
> + /* PPE's use a modified version of the booke behavior */
> + tb_env->flags = flags | PPC_DECR_UNDERFLOW_TRIGGERED;
> + } else {
> + tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
> + }
>
> tb_env->tb_freq = freq;
> tb_env->decr_freq = freq;
> diff --git a/hw/ppc/ppe42_machine.c b/hw/ppc/ppe42_machine.c
> new file mode 100644
> index 0000000000..0bc295da28
> --- /dev/null
> +++ b/hw/ppc/ppe42_machine.c
> @@ -0,0 +1,69 @@
> +
> +/*
> + * Test Machine for the IBM PPE42 processor
> + *
> + * Copyright (c) 2025, IBM Corporation.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/units.h"
> +#include "qemu/error-report.h"
> +#include "system/address-spaces.h"
> +#include "hw/boards.h"
> +#include "hw/ppc/ppc.h"
> +#include "system/system.h"
> +#include "system/reset.h"
> +#include "system/kvm.h"
> +
> +static void main_cpu_reset(void *opaque)
> +{
> + PowerPCCPU *cpu = opaque;
> +
> + cpu_reset(CPU(cpu));
There are no register settings ? Just asking
> +}
> +
> +static void ppe42_machine_init(MachineState *machine)
> +{
> + PowerPCCPU *cpu;
> + CPUPPCState *env;
> +
> + if (kvm_enabled()) {
> + error_report("machine %s does not support the KVM accelerator",
> + MACHINE_GET_CLASS(machine)->name);
> + exit(EXIT_FAILURE);
> + }
> +
> + /* init CPU */
> + cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
I would introduce a specific MachineState for the ppe42 Machine:
struct Ppe42MachineState {
/* Private */
MachineState parent_obj;
/* Public */
PowerPCCPU cpu;
};
and use qdev_realize() too.
> + env = &cpu->env;
> + if (PPC_INPUT(env) != PPC_FLAGS_INPUT_PPE42) {
> + error_report("Incompatible CPU, only PPE42 bus supported");
Can't we define valid_cpu_types instead ?
> + exit(1);
> + }
> +
> + qemu_register_reset(main_cpu_reset, cpu);
> +
> + /* This sets the decrementer timebase */
> + ppc_booke_timers_init(cpu, 37500000, PPC_TIMER_PPE);
> +
> + /* RAM */
> + if (machine->ram_size > 2 * GiB) {
2GB RAM ? really ?
> + error_report("RAM size more than 2 GiB is not supported");
> + exit(1);
> + }
> + memory_region_add_subregion(get_system_memory(), 0xfff80000, machine->ram);
> +}
> +
> +
> +static void ppe42_machine_class_init(MachineClass *mc)
> +{
> + mc->desc = "PPE42 Test Machine";
> + mc->init = ppe42_machine_init;
> + mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("PPE42XM");
> + mc->default_ram_id = "ram";
> + mc->default_ram_size = 1 * MiB;
> +}
> +
> +DEFINE_MACHINE("ppe42_machine", ppe42_machine_class_init)
> diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h
> index 8a14d623f8..cb51d704c6 100644
> --- a/include/hw/ppc/ppc.h
> +++ b/include/hw/ppc/ppc.h
> @@ -52,6 +52,7 @@ struct ppc_tb_t {
> #define PPC_DECR_UNDERFLOW_LEVEL (1 << 4) /* Decr interrupt active when
> * the most significant bit is 1.
> */
> +#define PPC_TIMER_PPE (1 << 5) /* Enable PPE support */
>
> uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
> void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq);
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/4] target/ppc: Add IBM PPE42 family of processors
2025-08-26 20:17 ` [PATCH v2 1/4] target/ppc: Add IBM PPE42 family of processors Glenn Miles
@ 2025-09-01 7:29 ` Cédric Le Goater
2025-09-02 16:59 ` Miles Glenn
0 siblings, 1 reply; 14+ messages in thread
From: Cédric Le Goater @ 2025-09-01 7:29 UTC (permalink / raw)
To: Glenn Miles, qemu-devel
Cc: qemu-ppc, npiggin, harshpb, thuth, rathc, richard.henderson
On 8/26/25 22:17, 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) and Exceptions.
>
> Does not yet support new PPE42 instructions and does not
> prevent access to some invalid instructions and registers
> (currently allows for access to invalid GPR's and CR fields).
>
> Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
Could you please split these changes : CPU, exceptions, MMU ?
Introduce the flags first in case they are needed.
Thanks,
C.
> ---
>
> Changes since previous version
> - Added "32-bit" wording to commit message
> - Added 'unlikely' specifier to hreg_compute_hflags_value conditional
> - Added PPE42_ prefix to ISR definitions
> - Moved ISR_MCS* definitions from excp_helper.c to cpu.h
> - Moved common cpu_init code to a common function
> - Added 'likely' specifier to gen_mtmsr conditional
> - Formatting changes to fit comments within 80 character limit
>
> target/ppc/cpu-models.c | 7 +
> target/ppc/cpu-models.h | 4 +
> target/ppc/cpu.h | 76 ++++++++++-
> target/ppc/cpu_init.c | 241 +++++++++++++++++++++++++++++------
> target/ppc/excp_helper.c | 163 +++++++++++++++++++++++
> target/ppc/helper_regs.c | 28 +++-
> target/ppc/tcg-excp_helper.c | 12 ++
> target/ppc/translate.c | 6 +-
> 8 files changed, 492 insertions(+), 45 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-models.h b/target/ppc/cpu-models.h
> index 72ad31ba50..c6cd27f390 100644
> --- a/target/ppc/cpu-models.h
> +++ b/target/ppc/cpu-models.h
> @@ -69,6 +69,10 @@ enum {
> /* Xilinx cores */
> CPU_POWERPC_X2VP4 = 0x20010820,
> CPU_POWERPC_X2VP20 = 0x20010860,
> + /* IBM PPE42 Family */
> + CPU_POWERPC_PPE42 = 0x42000000,
> + CPU_POWERPC_PPE42X = 0x42100000,
> + CPU_POWERPC_PPE42XM = 0x42200000,
> /* PowerPC 440 family */
> /* Generic PowerPC 440 */
> #define CPU_POWERPC_440 CPU_POWERPC_440GXf
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index 6b90543811..c68dd4f141 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -220,6 +220,8 @@ typedef enum powerpc_excp_t {
> POWERPC_EXCP_POWER10,
> /* POWER11 exception model */
> POWERPC_EXCP_POWER11,
> + /* PPE42 exception model */
> + POWERPC_EXCP_PPE42,
> } powerpc_excp_t;
>
> /*****************************************************************************/
> @@ -282,6 +284,8 @@ typedef enum powerpc_input_t {
> PPC_FLAGS_INPUT_POWER9,
> /* Freescale RCPU bus */
> PPC_FLAGS_INPUT_RCPU,
> + /* PPE42 bus */
> + PPC_FLAGS_INPUT_PPE42,
> } powerpc_input_t;
>
> #define PPC_INPUT(env) ((env)->bus_model)
> @@ -433,39 +437,64 @@ typedef enum {
> #define MSR_TM PPC_BIT_NR(31) /* Transactional Memory Available (Book3s) */
> #define MSR_CM PPC_BIT_NR(32) /* Computation mode for BookE hflags */
> #define MSR_ICM PPC_BIT_NR(33) /* Interrupt computation mode for BookE */
> +#define MSR_SEM0 PPC_BIT_NR(33) /* SIB Error Mask Bit 0 (PPE42) */
> +#define MSR_SEM1 PPC_BIT_NR(34) /* SIB Error Mask Bit 1 (PPE42) */
> +#define MSR_SEM2 PPC_BIT_NR(35) /* SIB Error Mask Bit 2 (PPE42) */
> #define MSR_GS PPC_BIT_NR(35) /* guest state for BookE */
> +#define MSR_SEM3 PPC_BIT_NR(36) /* SIB Error Mask Bit 3 (PPE42) */
> +#define MSR_SEM4 PPC_BIT_NR(37) /* SIB Error Mask Bit 4 (PPE42) */
> #define MSR_UCLE PPC_BIT_NR(37) /* User-mode cache lock enable for BookE */
> #define MSR_VR PPC_BIT_NR(38) /* altivec available x hflags */
> #define MSR_SPE PPC_BIT_NR(38) /* SPE enable for BookE x hflags */
> +#define MSR_SEM5 PPC_BIT_NR(38) /* SIB Error Mask Bit 5 (PPE42) */
> +#define MSR_SEM6 PPC_BIT_NR(39) /* SIB Error Mask Bit 6 (PPE42) */
> #define MSR_VSX PPC_BIT_NR(40) /* Vector Scalar Extension (>= 2.06)x hflags */
> +#define MSR_IS0 PPC_BIT_NR(40) /* Instance Specific Bit 0 (PPE42) */
> #define MSR_S PPC_BIT_NR(41) /* Secure state */
> +#define MSR_SIBRC0 PPC_BIT_NR(41) /* Last SIB return code Bit 0 (PPE42) */
> +#define MSR_SIBRC1 PPC_BIT_NR(42) /* Last SIB return code Bit 1 (PPE42) */
> +#define MSR_SIBRC2 PPC_BIT_NR(43) /* Last SIB return code Bit 2 (PPE42) */
> +#define MSR_LP PPC_BIT_NR(44) /* Low Priority (PPE42) */
> #define MSR_KEY PPC_BIT_NR(44) /* key bit on 603e */
> #define MSR_POW PPC_BIT_NR(45) /* Power management */
> #define MSR_WE PPC_BIT_NR(45) /* Wait State Enable on 405 */
> +#define MSR_IS1 PPC_BIT_NR(46) /* Instance Specific Bit 1 (PPE42) */
> #define MSR_TGPR PPC_BIT_NR(46) /* TGPR usage on 602/603 x */
> #define MSR_CE PPC_BIT_NR(46) /* Critical int. enable on embedded PPC x */
> #define MSR_ILE PPC_BIT_NR(47) /* Interrupt little-endian mode */
> +#define MSR_UIE PPC_BIT_NR(47) /* Unmaskable Interrupt Enable (PPE42) */
> #define MSR_EE PPC_BIT_NR(48) /* External interrupt enable */
> #define MSR_PR PPC_BIT_NR(49) /* Problem state hflags */
> #define MSR_FP PPC_BIT_NR(50) /* Floating point available hflags */
> #define MSR_ME PPC_BIT_NR(51) /* Machine check interrupt enable */
> #define MSR_FE0 PPC_BIT_NR(52) /* Floating point exception mode 0 */
> +#define MSR_IS2 PPC_BIT_NR(52) /* Instance Specific Bit 2 (PPE42) */
> +#define MSR_IS3 PPC_BIT_NR(53) /* Instance Specific Bit 3 (PPE42) */
> #define MSR_SE PPC_BIT_NR(53) /* Single-step trace enable x hflags */
> #define MSR_DWE PPC_BIT_NR(53) /* Debug wait enable on 405 x */
> #define MSR_UBLE PPC_BIT_NR(53) /* User BTB lock enable on e500 x */
> #define MSR_BE PPC_BIT_NR(54) /* Branch trace enable x hflags */
> #define MSR_DE PPC_BIT_NR(54) /* Debug int. enable on embedded PPC x */
> #define MSR_FE1 PPC_BIT_NR(55) /* Floating point exception mode 1 */
> +#define MSR_IPE PPC_BIT_NR(55) /* Imprecise Mode Enable (PPE42) */
> #define MSR_AL PPC_BIT_NR(56) /* AL bit on POWER */
> +#define MSR_SIBRCA0 PPC_BIT_NR(56) /* SIB Return Code Accumulator 0 (PPE42) */
> +#define MSR_SIBRCA1 PPC_BIT_NR(57) /* SIB Return Code Accumulator 1 (PPE42) */
> #define MSR_EP PPC_BIT_NR(57) /* Exception prefix on 601 */
> #define MSR_IR PPC_BIT_NR(58) /* Instruction relocate */
> #define MSR_IS PPC_BIT_NR(58) /* Instruction address space (BookE) */
> +#define MSR_SIBRCA2 PPC_BIT_NR(58) /* SIB Return Code Accumulator 2 (PPE42) */
> +#define MSR_SIBRCA3 PPC_BIT_NR(59) /* SIB Return Code Accumulator 3 (PPE42) */
> #define MSR_DR PPC_BIT_NR(59) /* Data relocate */
> #define MSR_DS PPC_BIT_NR(59) /* Data address space (BookE) */
> #define MSR_PE PPC_BIT_NR(60) /* Protection enable on 403 */
> +#define MSR_SIBRCA4 PPC_BIT_NR(60) /* SIB Return Code Accumulator 4 (PPE42) */
> +#define MSR_SIBRCA5 PPC_BIT_NR(61) /* SIB Return Code Accumulator 5 (PPE42) */
> #define MSR_PX PPC_BIT_NR(61) /* Protection exclusive on 403 x */
> #define MSR_PMM PPC_BIT_NR(61) /* Performance monitor mark on POWER x */
> #define MSR_RI PPC_BIT_NR(62) /* Recoverable interrupt 1 */
> +#define MSR_SIBRCA6 PPC_BIT_NR(62) /* SIB Return Code Accumulator 6 (PPE42) */
> +#define MSR_SIBRCA7 PPC_BIT_NR(63) /* SIB Return Code Accumulator 7 (PPE42) */
> #define MSR_LE PPC_BIT_NR(63) /* Little-endian mode 1 hflags */
>
> FIELD(MSR, SF, MSR_SF, 1)
> @@ -517,6 +546,9 @@ FIELD(MSR, PX, MSR_PX, 1)
> FIELD(MSR, PMM, MSR_PMM, 1)
> FIELD(MSR, RI, MSR_RI, 1)
> FIELD(MSR, LE, MSR_LE, 1)
> +FIELD(MSR, SEM, MSR_SEM6, 7)
> +FIELD(MSR, SIBRC, MSR_SIBRC2, 3)
> +FIELD(MSR, SIBRCA, MSR_SIBRCA7, 8)
>
> /*
> * FE0 and FE1 bits are not side-by-side
> @@ -730,6 +762,31 @@ FIELD(MSR, LE, MSR_LE, 1)
> #define ESR_VLEMI PPC_BIT(58) /* VLE operation */
> #define ESR_MIF PPC_BIT(62) /* Misaligned instruction (VLE) */
>
> +/* PPE42 Interrupt Status Register bits */
> +#define PPE42_ISR_SRSMS0 PPC_BIT_NR(48) /* Sys Reset State Machine State 0 */
> +#define PPE42_ISR_SRSMS1 PPC_BIT_NR(49) /* Sys Reset State Machine State 1 */
> +#define PPE42_ISR_SRSMS2 PPC_BIT_NR(50) /* Sys Reset State Machine State 2 */
> +#define PPE42_ISR_SRSMS3 PPC_BIT_NR(51) /* Sys Reset State Machine State 3 */
> +#define PPE42_ISR_EP PPC_BIT_NR(53) /* MSR[EE] Maskable Event Pending */
> +#define PPE42_ISR_PTR PPC_BIT_NR(56) /* Program Interrupt from trap */
> +#define PPE42_ISR_ST PPC_BIT_NR(57) /* Data Interrupt caused by store */
> +#define PPE42_ISR_MFE PPC_BIT_NR(60) /* Multiple Fault Error */
> +#define PPE42_ISR_MCS0 PPC_BIT_NR(61) /* Machine Check Status bit0 */
> +#define PPE42_ISR_MCS1 PPC_BIT_NR(62) /* Machine Check Status bit1 */
> +#define PPE42_ISR_MCS2 PPC_BIT_NR(63) /* Machine Check Status bit2 */
> +FIELD(PPE42_ISR, SRSMS, PPE42_ISR_SRSMS3, 4)
> +FIELD(PPE42_ISR, MCS, PPE42_ISR_MCS2, 3)
> +
> +/* PPE42 Machine Check Status field values */
> +#define PPE42_ISR_MCS_INSTRUCTION 0
> +#define PPE42_ISR_MCS_DATA_LOAD 1
> +#define PPE42_ISR_MCS_DATA_PRECISE_STORE 2
> +#define PPE42_ISR_MCS_DATA_IMPRECISE_STORE 3
> +#define PPE42_ISR_MCS_PROGRAM 4
> +#define PPE42_ISR_MCS_ISI 5
> +#define PPE42_ISR_MCS_ALIGNMENT 6
> +#define PPE42_ISR_MCS_DSI 7
> +
> /* Transaction EXception And Summary Register bits */
> #define TEXASR_FAILURE_PERSISTENT (63 - 7)
> #define TEXASR_DISALLOWED (63 - 8)
> @@ -785,6 +842,8 @@ enum {
> POWERPC_FLAG_SMT_1LPAR = 0x00800000,
> /* Has BHRB */
> POWERPC_FLAG_BHRB = 0x01000000,
> + /* Use PPE42-specific behavior */
> + POWERPC_FLAG_PPE42 = 0x02000000,
> };
>
> /*
> @@ -1750,9 +1809,12 @@ void ppc_compat_add_property(Object *obj, const char *name,
> #define SPR_BOOKE_CSRR0 (0x03A)
> #define SPR_BOOKE_CSRR1 (0x03B)
> #define SPR_BOOKE_DEAR (0x03D)
> +#define SPR_PPE42_EDR (0x03D)
> #define SPR_IAMR (0x03D)
> #define SPR_BOOKE_ESR (0x03E)
> +#define SPR_PPE42_ISR (0x03E)
> #define SPR_BOOKE_IVPR (0x03F)
> +#define SPR_PPE42_IVPR (0x03F)
> #define SPR_MPC_EIE (0x050)
> #define SPR_MPC_EID (0x051)
> #define SPR_MPC_NRI (0x052)
> @@ -1818,6 +1880,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
> #define SPR_TBU40 (0x11E)
> #define SPR_SVR (0x11E)
> #define SPR_BOOKE_PIR (0x11E)
> +#define SPR_PPE42_PIR (0x11E)
> #define SPR_PVR (0x11F)
> #define SPR_HSPRG0 (0x130)
> #define SPR_BOOKE_DBSR (0x130)
> @@ -1827,6 +1890,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
> #define SPR_BOOKE_EPCR (0x133)
> #define SPR_SPURR (0x134)
> #define SPR_BOOKE_DBCR0 (0x134)
> +#define SPR_PPE42_DBCR (0x134)
> #define SPR_IBCR (0x135)
> #define SPR_PURR (0x135)
> #define SPR_BOOKE_DBCR1 (0x135)
> @@ -1844,6 +1908,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
> #define SPR_HSRR1 (0x13B)
> #define SPR_BOOKE_IAC4 (0x13B)
> #define SPR_BOOKE_DAC1 (0x13C)
> +#define SPR_PPE42_DACR (0x13C)
> #define SPR_MMCRH (0x13C)
> #define SPR_DABR2 (0x13D)
> #define SPR_BOOKE_DAC2 (0x13D)
> @@ -1853,12 +1918,14 @@ void ppc_compat_add_property(Object *obj, const char *name,
> #define SPR_BOOKE_DVC2 (0x13F)
> #define SPR_LPIDR (0x13F)
> #define SPR_BOOKE_TSR (0x150)
> +#define SPR_PPE42_TSR (0x150)
> #define SPR_HMER (0x150)
> #define SPR_HMEER (0x151)
> #define SPR_PCR (0x152)
> #define SPR_HEIR (0x153)
> #define SPR_BOOKE_LPIDR (0x152)
> #define SPR_BOOKE_TCR (0x154)
> +#define SPR_PPE42_TCR (0x154)
> #define SPR_BOOKE_TLB0PS (0x158)
> #define SPR_BOOKE_TLB1PS (0x159)
> #define SPR_BOOKE_TLB2PS (0x15A)
> @@ -2528,6 +2595,12 @@ enum {
> PPC2_MEM_LWSYNC = 0x0000000000200000ULL,
> /* ISA 2.06 BCD assist instructions */
> PPC2_BCDA_ISA206 = 0x0000000000400000ULL,
> + /* PPE42 instructions */
> + PPC2_PPE42 = 0x0000000000800000ULL,
> + /* PPE42X instructions */
> + PPC2_PPE42X = 0x0000000001000000ULL,
> + /* PPE42XM instructions */
> + PPC2_PPE42XM = 0x0000000002000000ULL,
>
> #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \
> PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
> @@ -2537,7 +2610,8 @@ enum {
> PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \
> PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206 | \
> PPC2_ISA300 | PPC2_ISA310 | PPC2_MEM_LWSYNC | \
> - PPC2_BCDA_ISA206)
> + PPC2_BCDA_ISA206 | PPC2_PPE42 | PPC2_PPE42X | \
> + PPC2_PPE42XM)
> };
>
> /*****************************************************************************/
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index a0e77f2673..698d61bf0c 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)
> @@ -1679,6 +1720,30 @@ static void init_excp_4xx(CPUPPCState *env)
> #endif
> }
>
> +static void init_excp_ppe42(CPUPPCState *env)
> +{
> +#if !defined(CONFIG_USER_ONLY)
> + /* Machine Check vector changed after version 0 */
> + if (((env->spr[SPR_PVR] & 0xf00000ul) >> 20) == 0) {
> + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000000;
> + } else {
> + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000020;
> + }
> + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000040;
> + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000060;
> + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000080;
> + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x000000A0;
> + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x000000C0;
> + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x000000E0;
> + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000100;
> + env->excp_vectors[POWERPC_EXCP_FIT] = 0x00000120;
> + env->excp_vectors[POWERPC_EXCP_WDT] = 0x00000140;
> + env->ivpr_mask = 0xFFFFFE00UL;
> + /* Hardware reset vector */
> + env->hreset_vector = 0x00000040UL;
> +#endif
> +}
> +
> static void init_excp_MPC5xx(CPUPPCState *env)
> {
> #if !defined(CONFIG_USER_ONLY)
> @@ -2200,6 +2265,80 @@ POWERPC_FAMILY(405)(ObjectClass *oc, const void *data)
> POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
> }
>
> +static void init_proc_ppe42(CPUPPCState *env)
> +{
> + register_ppe42_sprs(env);
> +
> + init_excp_ppe42(env);
> + env->dcache_line_size = 32;
> + env->icache_line_size = 32;
> + /* Allocate hardware IRQ controller */
> + ppc40x_irq_init(env_archcpu(env));
> +
> + SET_FIT_PERIOD(8, 12, 16, 20);
> + SET_WDT_PERIOD(16, 20, 24, 28);
> +}
> +
> +static void ppe42_class_common_init(PowerPCCPUClass *pcc)
> +{
> + pcc->init_proc = init_proc_ppe42;
> + pcc->check_pow = check_pow_nocheck;
> + pcc->check_attn = check_attn_none;
> + pcc->insns_flags = PPC_INSNS_BASE |
> + PPC_WRTEE |
> + PPC_CACHE |
> + PPC_CACHE_DCBZ |
> + PPC_MEM_SYNC;
> + pcc->msr_mask = R_MSR_SEM_MASK |
> + (1ull << MSR_IS0) |
> + R_MSR_SIBRC_MASK |
> + (1ull << MSR_LP) |
> + (1ull << MSR_WE) |
> + (1ull << MSR_IS1) |
> + (1ull << MSR_UIE) |
> + (1ull << MSR_EE) |
> + (1ull << MSR_ME) |
> + (1ull << MSR_IS2) |
> + (1ull << MSR_IS3) |
> + (1ull << MSR_IPE) |
> + R_MSR_SIBRCA_MASK;
> + pcc->mmu_model = POWERPC_MMU_REAL;
> + pcc->excp_model = POWERPC_EXCP_PPE42;
> + pcc->bus_model = PPC_FLAGS_INPUT_PPE42;
> + pcc->bfd_mach = bfd_mach_ppc_403;
> + pcc->flags = POWERPC_FLAG_PPE42 | POWERPC_FLAG_BUS_CLK;
> +}
> +
> +POWERPC_FAMILY(ppe42)(ObjectClass *oc, const void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(oc);
> + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
> +
> + dc->desc = "PPE 42";
> + pcc->insns_flags2 = PPC2_PPE42;
> + ppe42_class_common_init(pcc);
> +}
> +
> +POWERPC_FAMILY(ppe42x)(ObjectClass *oc, const void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(oc);
> + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
> +
> + dc->desc = "PPE 42X";
> + pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X;
> + ppe42_class_common_init(pcc);
> +}
> +
> +POWERPC_FAMILY(ppe42xm)(ObjectClass *oc, const void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(oc);
> + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
> +
> + dc->desc = "PPE 42XM";
> + pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X | PPC2_PPE42XM;
> + ppe42_class_common_init(pcc);
> +}
> +
> static void init_proc_440EP(CPUPPCState *env)
> {
> register_BookE_sprs(env, 0x000000000000FFFFULL);
> @@ -6802,53 +6941,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 +7016,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 +7397,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)
> @@ -7725,6 +7880,18 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> * they can be read with "p $ivor0", "p $ivor1", etc.
> */
> break;
> + case POWERPC_EXCP_PPE42:
> + qemu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx "\n",
> + env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
> +
> + qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
> + " ISR " TARGET_FMT_lx " EDR " TARGET_FMT_lx "\n",
> + env->spr[SPR_PPE42_TCR], env->spr[SPR_PPE42_TSR],
> + env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
> +
> + qemu_fprintf(f, " PIR " TARGET_FMT_lx " IVPR " TARGET_FMT_lx "\n",
> + env->spr[SPR_PPE42_PIR], env->spr[SPR_PPE42_IVPR]);
> + break;
> case POWERPC_EXCP_40x:
> qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
> " ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n",
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 1efdc4066e..d8bca19fff 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -949,6 +949,125 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
> powerpc_set_excp_state(cpu, vector, new_msr);
> }
>
> +static void powerpc_excp_ppe42(PowerPCCPU *cpu, int excp)
> +{
> + CPUPPCState *env = &cpu->env;
> + target_ulong msr, new_msr, vector;
> + target_ulong mcs = PPE42_ISR_MCS_INSTRUCTION;
> + bool promote_unmaskable;
> +
> + msr = env->msr;
> +
> + /*
> + * New interrupt handler msr preserves SIBRC and ME unless explicitly
> + * overridden by the exception. All other MSR bits are zeroed out.
> + */
> + new_msr = env->msr & (((target_ulong)1 << MSR_ME) | R_MSR_SIBRC_MASK);
> +
> + /* HV emu assistance interrupt only exists on server arch 2.05 or later */
> + if (excp == POWERPC_EXCP_HV_EMU) {
> + excp = POWERPC_EXCP_PROGRAM;
> + }
> +
> + /*
> + * Unmaskable interrupts (Program, ISI, Alignment and DSI) are promoted to
> + * machine check if MSR_UIE is 0.
> + */
> + promote_unmaskable = !(msr & ((target_ulong)1 << MSR_UIE));
> +
> +
> + switch (excp) {
> + case POWERPC_EXCP_MCHECK: /* Machine check exception */
> + break;
> + case POWERPC_EXCP_DSI: /* Data storage exception */
> + trace_ppc_excp_dsi(env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
> + if (promote_unmaskable) {
> + excp = POWERPC_EXCP_MCHECK;
> + mcs = PPE42_ISR_MCS_DSI;
> + }
> + break;
> + case POWERPC_EXCP_ISI: /* Instruction storage exception */
> + trace_ppc_excp_isi(msr, env->nip);
> + if (promote_unmaskable) {
> + excp = POWERPC_EXCP_MCHECK;
> + mcs = PPE42_ISR_MCS_ISI;
> + }
> + break;
> + case POWERPC_EXCP_EXTERNAL: /* External input */
> + break;
> + case POWERPC_EXCP_ALIGN: /* Alignment exception */
> + if (promote_unmaskable) {
> + excp = POWERPC_EXCP_MCHECK;
> + mcs = PPE42_ISR_MCS_ALIGNMENT;
> + }
> + break;
> + case POWERPC_EXCP_PROGRAM: /* Program exception */
> + if (promote_unmaskable) {
> + excp = POWERPC_EXCP_MCHECK;
> + mcs = PPE42_ISR_MCS_PROGRAM;
> + }
> + switch (env->error_code & ~0xF) {
> + case POWERPC_EXCP_INVAL:
> + trace_ppc_excp_inval(env->nip);
> + env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_PTR);
> + break;
> + case POWERPC_EXCP_TRAP:
> + env->spr[SPR_PPE42_ISR] |= ((target_ulong)1 << PPE42_ISR_PTR);
> + break;
> + default:
> + /* Should never occur */
> + cpu_abort(env_cpu(env), "Invalid program exception %d. Aborting\n",
> + env->error_code);
> + break;
> + }
> +#ifdef CONFIG_TCG
> + env->spr[SPR_PPE42_EDR] = ppc_ldl_code(env, env->nip);
> +#endif
> + break;
> + case POWERPC_EXCP_DECR: /* Decrementer exception */
> + break;
> + case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
> + trace_ppc_excp_print("FIT");
> + break;
> + case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
> + trace_ppc_excp_print("WDT");
> + break;
> + case POWERPC_EXCP_RESET: /* System reset exception */
> + /* reset exceptions don't have ME set */
> + new_msr &= ~((target_ulong)1 << MSR_ME);
> + break;
> + default:
> + cpu_abort(env_cpu(env), "Invalid PPE42 exception %d. Aborting\n",
> + excp);
> + break;
> + }
> +
> + env->spr[SPR_SRR0] = env->nip;
> + env->spr[SPR_SRR1] = msr;
> +
> + vector = env->excp_vectors[excp];
> + if (vector == (target_ulong)-1ULL) {
> + cpu_abort(env_cpu(env),
> + "Raised an exception without defined vector %d\n", excp);
> + }
> + vector |= env->spr[SPR_PPE42_IVPR];
> +
> + if (excp == POWERPC_EXCP_MCHECK) {
> + /* Also set the Machine Check Status (MCS) */
> + env->spr[SPR_PPE42_ISR] &= ~R_PPE42_ISR_MCS_MASK;
> + env->spr[SPR_PPE42_ISR] |= (mcs & R_PPE42_ISR_MCS_MASK);
> + env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_MFE);
> +
> + /* Machine checks halt execution if MSR_ME is 0 */
> + powerpc_mcheck_checkstop(env);
> +
> + /* machine check exceptions don't have ME set */
> + new_msr &= ~((target_ulong)1 << MSR_ME);
> + }
> +
> + powerpc_set_excp_state(cpu, vector, new_msr);
> +}
> +
> static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
> {
> CPUPPCState *env = &cpu->env;
> @@ -1589,6 +1708,9 @@ void powerpc_excp(PowerPCCPU *cpu, int excp)
> case POWERPC_EXCP_POWER11:
> powerpc_excp_books(cpu, excp);
> break;
> + case POWERPC_EXCP_PPE42:
> + powerpc_excp_ppe42(cpu, excp);
> + break;
> default:
> g_assert_not_reached();
> }
> @@ -1945,6 +2067,43 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env,
> }
> #endif /* TARGET_PPC64 */
>
> +static int ppe42_next_unmasked_interrupt(CPUPPCState *env)
> +{
> + bool async_deliver;
> +
> + /* External reset */
> + if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
> + return PPC_INTERRUPT_RESET;
> + }
> + /* Machine check exception */
> + if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
> + return PPC_INTERRUPT_MCK;
> + }
> +
> + async_deliver = FIELD_EX64(env->msr, MSR, EE);
> +
> + if (async_deliver != 0) {
> + /* Watchdog timer */
> + if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
> + return PPC_INTERRUPT_WDT;
> + }
> + /* External Interrupt */
> + if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
> + return PPC_INTERRUPT_EXT;
> + }
> + /* Fixed interval timer */
> + if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
> + return PPC_INTERRUPT_FIT;
> + }
> + /* Decrementer exception */
> + if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
> + return PPC_INTERRUPT_DECR;
> + }
> + }
> +
> + return 0;
> +}
> +
> static int ppc_next_unmasked_interrupt(CPUPPCState *env)
> {
> uint32_t pending_interrupts = env->pending_interrupts;
> @@ -1970,6 +2129,10 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
> }
> #endif
>
> + if (env->excp_model == POWERPC_EXCP_PPE42) {
> + return ppe42_next_unmasked_interrupt(env);
> + }
> +
> /* External reset */
> if (pending_interrupts & PPC_INTERRUPT_RESET) {
> return PPC_INTERRUPT_RESET;
> diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
> index 7e5726871e..9953d73884 100644
> --- a/target/ppc/helper_regs.c
> +++ b/target/ppc/helper_regs.c
> @@ -186,6 +186,10 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
> if (env->spr[SPR_LPCR] & LPCR_HR) {
> hflags |= 1 << HFLAGS_HR;
> }
> + if (unlikely(ppc_flags & POWERPC_FLAG_PPE42)) {
> + /* PPE42 has a single address space and no problem state */
> + msr = 0;
> + }
>
> #ifndef CONFIG_USER_ONLY
> if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
> @@ -306,9 +310,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)) {
> @@ -319,8 +320,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 MSR has bits overlapping with others */
> + if (!(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
> @@ -462,6 +469,17 @@ void register_generic_sprs(PowerPCCPU *cpu)
> SPR_NOACCESS, SPR_NOACCESS,
> &spr_read_generic, &spr_write_generic,
> 0x00000000);
> +
> + if (env->insns_flags2 & PPC2_PPE42) {
> + spr_register(env, SPR_PVR, "PVR",
> + SPR_NOACCESS, SPR_NOACCESS,
> + &spr_read_generic, SPR_NOACCESS,
> + pcc->pvr);
> +
> + /* PPE42 doesn't support additional SPRG regs or timebase */
> + return;
> + }
> +
> spr_register(env, SPR_SPRG1, "SPRG1",
> SPR_NOACCESS, SPR_NOACCESS,
> &spr_read_generic, &spr_write_generic,
> diff --git a/target/ppc/tcg-excp_helper.c b/target/ppc/tcg-excp_helper.c
> index f835be5156..edecfb8572 100644
> --- a/target/ppc/tcg-excp_helper.c
> +++ b/target/ppc/tcg-excp_helper.c
> @@ -229,6 +229,18 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
> case POWERPC_MMU_BOOKE206:
> env->spr[SPR_BOOKE_DEAR] = vaddr;
> break;
> + case POWERPC_MMU_REAL:
> + if (env->flags & POWERPC_FLAG_PPE42) {
> + env->spr[SPR_PPE42_EDR] = vaddr;
> + if (access_type == MMU_DATA_STORE) {
> + env->spr[SPR_PPE42_ISR] |= PPE42_ISR_ST;
> + } else {
> + env->spr[SPR_PPE42_ISR] &= ~PPE42_ISR_ST;
> + }
> + } else {
> + env->spr[SPR_DAR] = vaddr;
> + }
> + break;
> default:
> env->spr[SPR_DAR] = vaddr;
> break;
> 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
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 3/4] hw/ppc: Add a test machine for the IBM PPE42 CPU
2025-09-01 7:25 ` Cédric Le Goater
@ 2025-09-01 10:15 ` BALATON Zoltan
2025-09-02 16:56 ` Miles Glenn
1 sibling, 0 replies; 14+ messages in thread
From: BALATON Zoltan @ 2025-09-01 10:15 UTC (permalink / raw)
To: Cédric Le Goater
Cc: Glenn Miles, qemu-devel, qemu-ppc, npiggin, harshpb, thuth, rathc,
richard.henderson
[-- Attachment #1: Type: text/plain, Size: 407 bytes --]
On Mon, 1 Sep 2025, Cédric Le Goater wrote:
> On 8/26/25 22:17, Glenn Miles wrote:
> I would introduce a specific MachineState for the ppe42 Machine:
>
> struct Ppe42MachineState {
> /* Private */
> MachineState parent_obj;
> /* Public */
Private/public comments are not recommended any more for QOM objects
since commit 067109a11c8 just an empty line after parent_obj.
Regards,
BALATON Zoltan
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 3/4] hw/ppc: Add a test machine for the IBM PPE42 CPU
2025-09-01 7:25 ` Cédric Le Goater
2025-09-01 10:15 ` BALATON Zoltan
@ 2025-09-02 16:56 ` Miles Glenn
2025-09-03 22:50 ` Miles Glenn
1 sibling, 1 reply; 14+ messages in thread
From: Miles Glenn @ 2025-09-02 16:56 UTC (permalink / raw)
To: Cédric Le Goater, qemu-devel
Cc: qemu-ppc, npiggin, harshpb, thuth, rathc, richard.henderson
On Mon, 2025-09-01 at 09:25 +0200, Cédric Le Goater wrote:
> On 8/26/25 22:17, Glenn Miles wrote:
> > Adds a test machine for the IBM PPE42 processor, including a
> > DEC, FIT, WDT and 1MB of ram.
> >
> > The purpose of this machine is only to provide a generic platform
> > for testing instructions of the recently added PPE42 processor
> > model which is used extensively in the IBM Power9, Power10 and
> > future Power server processors.
> >
> > Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
> > ---
> >
> > Changes from previous version
> > - Added ppe42_machine.c to MAINTAINERS file with self as maintainer
> >
> > MAINTAINERS | 6 ++++
> > hw/ppc/Kconfig | 9 ++++++
> > hw/ppc/meson.build | 2 ++
> > hw/ppc/ppc_booke.c | 7 ++++-
> > hw/ppc/ppe42_machine.c | 69 ++++++++++++++++++++++++++++++++++++++++++
> > include/hw/ppc/ppc.h | 1 +
> > 6 files changed, 93 insertions(+), 1 deletion(-)
> > create mode 100644 hw/ppc/ppe42_machine.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index a07086ed76..52fa303e0a 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1531,6 +1531,12 @@ F: include/hw/pci-host/grackle.h
> > F: pc-bios/qemu_vga.ndrv
> > F: tests/functional/test_ppc_mac.py
> >
> > +PPE42
> > +M: Glenn Miles <milesg@linux.ibm.com>
> > +L: qemu-ppc@nongnu.org
> > +S: Odd Fixes
> > +F: hw/ppc/ppe42_machine.c
> > +
> > PReP
> > M: Hervé Poussineau <hpoussin@reactos.org>
> > L: qemu-ppc@nongnu.org
> > diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
> > index ced6bbc740..3fdea5919c 100644
> > --- a/hw/ppc/Kconfig
> > +++ b/hw/ppc/Kconfig
> > @@ -44,6 +44,15 @@ config POWERNV
> > select SSI_M25P80
> > select PNV_SPI
> >
> > +config PPC405
> > + bool
> > + default y
> > + depends on PPC
> > + select M48T59
> > + select PFLASH_CFI02
> > + select PPC4XX
> > + select SERIAL
> > +
> > config PPC440
> > bool
> > default y
> > diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
> > index 9893f8adeb..170b90ae7d 100644
> > --- a/hw/ppc/meson.build
> > +++ b/hw/ppc/meson.build
> > @@ -57,6 +57,8 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
> > 'pnv_n1_chiplet.c',
> > ))
> > # PowerPC 4xx boards
> > +ppc_ss.add(when: 'CONFIG_PPC405', if_true: files(
> > + 'ppe42_machine.c'))
> > ppc_ss.add(when: 'CONFIG_PPC440', if_true: files(
> > 'ppc440_bamboo.c',
> > 'ppc440_uc.c'))
> > diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c
> > index 3872ae2822..13403a56b1 100644
> > --- a/hw/ppc/ppc_booke.c
> > +++ b/hw/ppc/ppc_booke.c
> > @@ -352,7 +352,12 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
> > booke_timer = g_new0(booke_timer_t, 1);
> >
> > cpu->env.tb_env = tb_env;
> > - tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
> > + if (flags & PPC_TIMER_PPE) {
>
> PPC_TIMER_PPE definition should be introduced in its own patch.
>
Ok, will do.
>
> > + /* PPE's use a modified version of the booke behavior */
> > + tb_env->flags = flags | PPC_DECR_UNDERFLOW_TRIGGERED;
> > + } else {
> > + tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
> > + }
> >
> > tb_env->tb_freq = freq;
> > tb_env->decr_freq = freq;
> > diff --git a/hw/ppc/ppe42_machine.c b/hw/ppc/ppe42_machine.c
> > new file mode 100644
> > index 0000000000..0bc295da28
> > --- /dev/null
> > +++ b/hw/ppc/ppe42_machine.c
> > @@ -0,0 +1,69 @@
> > +
> > +/*
> > + * Test Machine for the IBM PPE42 processor
> > + *
> > + * Copyright (c) 2025, IBM Corporation.
> > + *
> > + * SPDX-License-Identifier: GPL-2.0-or-later
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qemu/units.h"
> > +#include "qemu/error-report.h"
> > +#include "system/address-spaces.h"
> > +#include "hw/boards.h"
> > +#include "hw/ppc/ppc.h"
> > +#include "system/system.h"
> > +#include "system/reset.h"
> > +#include "system/kvm.h"
> > +
> > +static void main_cpu_reset(void *opaque)
> > +{
> > + PowerPCCPU *cpu = opaque;
> > +
> > + cpu_reset(CPU(cpu));
>
> There are no register settings ? Just asking
>
Admittedly, I did not do much digging into the reset case. I'll look
into it.
> > +}
> > +
> > +static void ppe42_machine_init(MachineState *machine)
> > +{
> > + PowerPCCPU *cpu;
> > + CPUPPCState *env;
> > +
> > + if (kvm_enabled()) {
> > + error_report("machine %s does not support the KVM accelerator",
> > + MACHINE_GET_CLASS(machine)->name);
> > + exit(EXIT_FAILURE);
> > + }
> > +
> > + /* init CPU */
> > + cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
>
> I would introduce a specific MachineState for the ppe42 Machine:
>
> struct Ppe42MachineState {
> /* Private */
> MachineState parent_obj;
> /* Public */
>
> PowerPCCPU cpu;
> };
>
> and use qdev_realize() too.
>
>
Sure, no problem.
> > + env = &cpu->env;
> > + if (PPC_INPUT(env) != PPC_FLAGS_INPUT_PPE42) {
> > + error_report("Incompatible CPU, only PPE42 bus supported");
>
> Can't we define valid_cpu_types instead ?
>
Ah, I was not aware of that option. Thanks, I'll give that a try.
> > + exit(1);
> > + }
> > +
> > + qemu_register_reset(main_cpu_reset, cpu);
> > +
> > + /* This sets the decrementer timebase */
> > + ppc_booke_timers_init(cpu, 37500000, PPC_TIMER_PPE);
> > +
> > + /* RAM */
> > + if (machine->ram_size > 2 * GiB) {
>
> 2GB RAM ? really ?
>
Hmm, not sure what I was thinking there. Since the ram starts at
address 0xfff80000, I'll change that to 512K.
Thanks for taking a look!
Glenn
> > + error_report("RAM size more than 2 GiB is not supported");
> > + exit(1);
> > + }
> > + memory_region_add_subregion(get_system_memory(), 0xfff80000, machine->ram);
> > +}
> > +
> > +
> > +static void ppe42_machine_class_init(MachineClass *mc)
> > +{
> > + mc->desc = "PPE42 Test Machine";
> > + mc->init = ppe42_machine_init;
> > + mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("PPE42XM");
> > + mc->default_ram_id = "ram";
> > + mc->default_ram_size = 1 * MiB;
> > +}
> > +
> > +DEFINE_MACHINE("ppe42_machine", ppe42_machine_class_init)
> > diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h
> > index 8a14d623f8..cb51d704c6 100644
> > --- a/include/hw/ppc/ppc.h
> > +++ b/include/hw/ppc/ppc.h
> > @@ -52,6 +52,7 @@ struct ppc_tb_t {
> > #define PPC_DECR_UNDERFLOW_LEVEL (1 << 4) /* Decr interrupt active when
> > * the most significant bit is 1.
> > */
> > +#define PPC_TIMER_PPE (1 << 5) /* Enable PPE support */
> >
> > uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
> > void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq);
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/4] target/ppc: Add IBM PPE42 family of processors
2025-09-01 7:29 ` Cédric Le Goater
@ 2025-09-02 16:59 ` Miles Glenn
0 siblings, 0 replies; 14+ messages in thread
From: Miles Glenn @ 2025-09-02 16:59 UTC (permalink / raw)
To: Cédric Le Goater, qemu-devel
Cc: qemu-ppc, npiggin, harshpb, thuth, rathc, richard.henderson
On Mon, 2025-09-01 at 09:29 +0200, Cédric Le Goater wrote:
> On 8/26/25 22:17, 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) and Exceptions.
> >
> > Does not yet support new PPE42 instructions and does not
> > prevent access to some invalid instructions and registers
> > (currently allows for access to invalid GPR's and CR fields).
> >
> > Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
>
> Could you please split these changes : CPU, exceptions, MMU ?
> Introduce the flags first in case they are needed.
>
> Thanks,
>
> C.
>
>
Will do!
Thanks,
Glenn
>
>
>
> > ---
> >
> > Changes since previous version
> > - Added "32-bit" wording to commit message
> > - Added 'unlikely' specifier to hreg_compute_hflags_value conditional
> > - Added PPE42_ prefix to ISR definitions
> > - Moved ISR_MCS* definitions from excp_helper.c to cpu.h
> > - Moved common cpu_init code to a common function
> > - Added 'likely' specifier to gen_mtmsr conditional
> > - Formatting changes to fit comments within 80 character limit
> >
> > target/ppc/cpu-models.c | 7 +
> > target/ppc/cpu-models.h | 4 +
> > target/ppc/cpu.h | 76 ++++++++++-
> > target/ppc/cpu_init.c | 241 +++++++++++++++++++++++++++++------
> > target/ppc/excp_helper.c | 163 +++++++++++++++++++++++
> > target/ppc/helper_regs.c | 28 +++-
> > target/ppc/tcg-excp_helper.c | 12 ++
> > target/ppc/translate.c | 6 +-
> > 8 files changed, 492 insertions(+), 45 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-models.h b/target/ppc/cpu-models.h
> > index 72ad31ba50..c6cd27f390 100644
> > --- a/target/ppc/cpu-models.h
> > +++ b/target/ppc/cpu-models.h
> > @@ -69,6 +69,10 @@ enum {
> > /* Xilinx cores */
> > CPU_POWERPC_X2VP4 = 0x20010820,
> > CPU_POWERPC_X2VP20 = 0x20010860,
> > + /* IBM PPE42 Family */
> > + CPU_POWERPC_PPE42 = 0x42000000,
> > + CPU_POWERPC_PPE42X = 0x42100000,
> > + CPU_POWERPC_PPE42XM = 0x42200000,
> > /* PowerPC 440 family */
> > /* Generic PowerPC 440 */
> > #define CPU_POWERPC_440 CPU_POWERPC_440GXf
> > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > index 6b90543811..c68dd4f141 100644
> > --- a/target/ppc/cpu.h
> > +++ b/target/ppc/cpu.h
> > @@ -220,6 +220,8 @@ typedef enum powerpc_excp_t {
> > POWERPC_EXCP_POWER10,
> > /* POWER11 exception model */
> > POWERPC_EXCP_POWER11,
> > + /* PPE42 exception model */
> > + POWERPC_EXCP_PPE42,
> > } powerpc_excp_t;
> >
> > /*****************************************************************************/
> > @@ -282,6 +284,8 @@ typedef enum powerpc_input_t {
> > PPC_FLAGS_INPUT_POWER9,
> > /* Freescale RCPU bus */
> > PPC_FLAGS_INPUT_RCPU,
> > + /* PPE42 bus */
> > + PPC_FLAGS_INPUT_PPE42,
> > } powerpc_input_t;
> >
> > #define PPC_INPUT(env) ((env)->bus_model)
> > @@ -433,39 +437,64 @@ typedef enum {
> > #define MSR_TM PPC_BIT_NR(31) /* Transactional Memory Available (Book3s) */
> > #define MSR_CM PPC_BIT_NR(32) /* Computation mode for BookE hflags */
> > #define MSR_ICM PPC_BIT_NR(33) /* Interrupt computation mode for BookE */
> > +#define MSR_SEM0 PPC_BIT_NR(33) /* SIB Error Mask Bit 0 (PPE42) */
> > +#define MSR_SEM1 PPC_BIT_NR(34) /* SIB Error Mask Bit 1 (PPE42) */
> > +#define MSR_SEM2 PPC_BIT_NR(35) /* SIB Error Mask Bit 2 (PPE42) */
> > #define MSR_GS PPC_BIT_NR(35) /* guest state for BookE */
> > +#define MSR_SEM3 PPC_BIT_NR(36) /* SIB Error Mask Bit 3 (PPE42) */
> > +#define MSR_SEM4 PPC_BIT_NR(37) /* SIB Error Mask Bit 4 (PPE42) */
> > #define MSR_UCLE PPC_BIT_NR(37) /* User-mode cache lock enable for BookE */
> > #define MSR_VR PPC_BIT_NR(38) /* altivec available x hflags */
> > #define MSR_SPE PPC_BIT_NR(38) /* SPE enable for BookE x hflags */
> > +#define MSR_SEM5 PPC_BIT_NR(38) /* SIB Error Mask Bit 5 (PPE42) */
> > +#define MSR_SEM6 PPC_BIT_NR(39) /* SIB Error Mask Bit 6 (PPE42) */
> > #define MSR_VSX PPC_BIT_NR(40) /* Vector Scalar Extension (>= 2.06)x hflags */
> > +#define MSR_IS0 PPC_BIT_NR(40) /* Instance Specific Bit 0 (PPE42) */
> > #define MSR_S PPC_BIT_NR(41) /* Secure state */
> > +#define MSR_SIBRC0 PPC_BIT_NR(41) /* Last SIB return code Bit 0 (PPE42) */
> > +#define MSR_SIBRC1 PPC_BIT_NR(42) /* Last SIB return code Bit 1 (PPE42) */
> > +#define MSR_SIBRC2 PPC_BIT_NR(43) /* Last SIB return code Bit 2 (PPE42) */
> > +#define MSR_LP PPC_BIT_NR(44) /* Low Priority (PPE42) */
> > #define MSR_KEY PPC_BIT_NR(44) /* key bit on 603e */
> > #define MSR_POW PPC_BIT_NR(45) /* Power management */
> > #define MSR_WE PPC_BIT_NR(45) /* Wait State Enable on 405 */
> > +#define MSR_IS1 PPC_BIT_NR(46) /* Instance Specific Bit 1 (PPE42) */
> > #define MSR_TGPR PPC_BIT_NR(46) /* TGPR usage on 602/603 x */
> > #define MSR_CE PPC_BIT_NR(46) /* Critical int. enable on embedded PPC x */
> > #define MSR_ILE PPC_BIT_NR(47) /* Interrupt little-endian mode */
> > +#define MSR_UIE PPC_BIT_NR(47) /* Unmaskable Interrupt Enable (PPE42) */
> > #define MSR_EE PPC_BIT_NR(48) /* External interrupt enable */
> > #define MSR_PR PPC_BIT_NR(49) /* Problem state hflags */
> > #define MSR_FP PPC_BIT_NR(50) /* Floating point available hflags */
> > #define MSR_ME PPC_BIT_NR(51) /* Machine check interrupt enable */
> > #define MSR_FE0 PPC_BIT_NR(52) /* Floating point exception mode 0 */
> > +#define MSR_IS2 PPC_BIT_NR(52) /* Instance Specific Bit 2 (PPE42) */
> > +#define MSR_IS3 PPC_BIT_NR(53) /* Instance Specific Bit 3 (PPE42) */
> > #define MSR_SE PPC_BIT_NR(53) /* Single-step trace enable x hflags */
> > #define MSR_DWE PPC_BIT_NR(53) /* Debug wait enable on 405 x */
> > #define MSR_UBLE PPC_BIT_NR(53) /* User BTB lock enable on e500 x */
> > #define MSR_BE PPC_BIT_NR(54) /* Branch trace enable x hflags */
> > #define MSR_DE PPC_BIT_NR(54) /* Debug int. enable on embedded PPC x */
> > #define MSR_FE1 PPC_BIT_NR(55) /* Floating point exception mode 1 */
> > +#define MSR_IPE PPC_BIT_NR(55) /* Imprecise Mode Enable (PPE42) */
> > #define MSR_AL PPC_BIT_NR(56) /* AL bit on POWER */
> > +#define MSR_SIBRCA0 PPC_BIT_NR(56) /* SIB Return Code Accumulator 0 (PPE42) */
> > +#define MSR_SIBRCA1 PPC_BIT_NR(57) /* SIB Return Code Accumulator 1 (PPE42) */
> > #define MSR_EP PPC_BIT_NR(57) /* Exception prefix on 601 */
> > #define MSR_IR PPC_BIT_NR(58) /* Instruction relocate */
> > #define MSR_IS PPC_BIT_NR(58) /* Instruction address space (BookE) */
> > +#define MSR_SIBRCA2 PPC_BIT_NR(58) /* SIB Return Code Accumulator 2 (PPE42) */
> > +#define MSR_SIBRCA3 PPC_BIT_NR(59) /* SIB Return Code Accumulator 3 (PPE42) */
> > #define MSR_DR PPC_BIT_NR(59) /* Data relocate */
> > #define MSR_DS PPC_BIT_NR(59) /* Data address space (BookE) */
> > #define MSR_PE PPC_BIT_NR(60) /* Protection enable on 403 */
> > +#define MSR_SIBRCA4 PPC_BIT_NR(60) /* SIB Return Code Accumulator 4 (PPE42) */
> > +#define MSR_SIBRCA5 PPC_BIT_NR(61) /* SIB Return Code Accumulator 5 (PPE42) */
> > #define MSR_PX PPC_BIT_NR(61) /* Protection exclusive on 403 x */
> > #define MSR_PMM PPC_BIT_NR(61) /* Performance monitor mark on POWER x */
> > #define MSR_RI PPC_BIT_NR(62) /* Recoverable interrupt 1 */
> > +#define MSR_SIBRCA6 PPC_BIT_NR(62) /* SIB Return Code Accumulator 6 (PPE42) */
> > +#define MSR_SIBRCA7 PPC_BIT_NR(63) /* SIB Return Code Accumulator 7 (PPE42) */
> > #define MSR_LE PPC_BIT_NR(63) /* Little-endian mode 1 hflags */
> >
> > FIELD(MSR, SF, MSR_SF, 1)
> > @@ -517,6 +546,9 @@ FIELD(MSR, PX, MSR_PX, 1)
> > FIELD(MSR, PMM, MSR_PMM, 1)
> > FIELD(MSR, RI, MSR_RI, 1)
> > FIELD(MSR, LE, MSR_LE, 1)
> > +FIELD(MSR, SEM, MSR_SEM6, 7)
> > +FIELD(MSR, SIBRC, MSR_SIBRC2, 3)
> > +FIELD(MSR, SIBRCA, MSR_SIBRCA7, 8)
> >
> > /*
> > * FE0 and FE1 bits are not side-by-side
> > @@ -730,6 +762,31 @@ FIELD(MSR, LE, MSR_LE, 1)
> > #define ESR_VLEMI PPC_BIT(58) /* VLE operation */
> > #define ESR_MIF PPC_BIT(62) /* Misaligned instruction (VLE) */
> >
> > +/* PPE42 Interrupt Status Register bits */
> > +#define PPE42_ISR_SRSMS0 PPC_BIT_NR(48) /* Sys Reset State Machine State 0 */
> > +#define PPE42_ISR_SRSMS1 PPC_BIT_NR(49) /* Sys Reset State Machine State 1 */
> > +#define PPE42_ISR_SRSMS2 PPC_BIT_NR(50) /* Sys Reset State Machine State 2 */
> > +#define PPE42_ISR_SRSMS3 PPC_BIT_NR(51) /* Sys Reset State Machine State 3 */
> > +#define PPE42_ISR_EP PPC_BIT_NR(53) /* MSR[EE] Maskable Event Pending */
> > +#define PPE42_ISR_PTR PPC_BIT_NR(56) /* Program Interrupt from trap */
> > +#define PPE42_ISR_ST PPC_BIT_NR(57) /* Data Interrupt caused by store */
> > +#define PPE42_ISR_MFE PPC_BIT_NR(60) /* Multiple Fault Error */
> > +#define PPE42_ISR_MCS0 PPC_BIT_NR(61) /* Machine Check Status bit0 */
> > +#define PPE42_ISR_MCS1 PPC_BIT_NR(62) /* Machine Check Status bit1 */
> > +#define PPE42_ISR_MCS2 PPC_BIT_NR(63) /* Machine Check Status bit2 */
> > +FIELD(PPE42_ISR, SRSMS, PPE42_ISR_SRSMS3, 4)
> > +FIELD(PPE42_ISR, MCS, PPE42_ISR_MCS2, 3)
> > +
> > +/* PPE42 Machine Check Status field values */
> > +#define PPE42_ISR_MCS_INSTRUCTION 0
> > +#define PPE42_ISR_MCS_DATA_LOAD 1
> > +#define PPE42_ISR_MCS_DATA_PRECISE_STORE 2
> > +#define PPE42_ISR_MCS_DATA_IMPRECISE_STORE 3
> > +#define PPE42_ISR_MCS_PROGRAM 4
> > +#define PPE42_ISR_MCS_ISI 5
> > +#define PPE42_ISR_MCS_ALIGNMENT 6
> > +#define PPE42_ISR_MCS_DSI 7
> > +
> > /* Transaction EXception And Summary Register bits */
> > #define TEXASR_FAILURE_PERSISTENT (63 - 7)
> > #define TEXASR_DISALLOWED (63 - 8)
> > @@ -785,6 +842,8 @@ enum {
> > POWERPC_FLAG_SMT_1LPAR = 0x00800000,
> > /* Has BHRB */
> > POWERPC_FLAG_BHRB = 0x01000000,
> > + /* Use PPE42-specific behavior */
> > + POWERPC_FLAG_PPE42 = 0x02000000,
> > };
> >
> > /*
> > @@ -1750,9 +1809,12 @@ void ppc_compat_add_property(Object *obj, const char *name,
> > #define SPR_BOOKE_CSRR0 (0x03A)
> > #define SPR_BOOKE_CSRR1 (0x03B)
> > #define SPR_BOOKE_DEAR (0x03D)
> > +#define SPR_PPE42_EDR (0x03D)
> > #define SPR_IAMR (0x03D)
> > #define SPR_BOOKE_ESR (0x03E)
> > +#define SPR_PPE42_ISR (0x03E)
> > #define SPR_BOOKE_IVPR (0x03F)
> > +#define SPR_PPE42_IVPR (0x03F)
> > #define SPR_MPC_EIE (0x050)
> > #define SPR_MPC_EID (0x051)
> > #define SPR_MPC_NRI (0x052)
> > @@ -1818,6 +1880,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
> > #define SPR_TBU40 (0x11E)
> > #define SPR_SVR (0x11E)
> > #define SPR_BOOKE_PIR (0x11E)
> > +#define SPR_PPE42_PIR (0x11E)
> > #define SPR_PVR (0x11F)
> > #define SPR_HSPRG0 (0x130)
> > #define SPR_BOOKE_DBSR (0x130)
> > @@ -1827,6 +1890,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
> > #define SPR_BOOKE_EPCR (0x133)
> > #define SPR_SPURR (0x134)
> > #define SPR_BOOKE_DBCR0 (0x134)
> > +#define SPR_PPE42_DBCR (0x134)
> > #define SPR_IBCR (0x135)
> > #define SPR_PURR (0x135)
> > #define SPR_BOOKE_DBCR1 (0x135)
> > @@ -1844,6 +1908,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
> > #define SPR_HSRR1 (0x13B)
> > #define SPR_BOOKE_IAC4 (0x13B)
> > #define SPR_BOOKE_DAC1 (0x13C)
> > +#define SPR_PPE42_DACR (0x13C)
> > #define SPR_MMCRH (0x13C)
> > #define SPR_DABR2 (0x13D)
> > #define SPR_BOOKE_DAC2 (0x13D)
> > @@ -1853,12 +1918,14 @@ void ppc_compat_add_property(Object *obj, const char *name,
> > #define SPR_BOOKE_DVC2 (0x13F)
> > #define SPR_LPIDR (0x13F)
> > #define SPR_BOOKE_TSR (0x150)
> > +#define SPR_PPE42_TSR (0x150)
> > #define SPR_HMER (0x150)
> > #define SPR_HMEER (0x151)
> > #define SPR_PCR (0x152)
> > #define SPR_HEIR (0x153)
> > #define SPR_BOOKE_LPIDR (0x152)
> > #define SPR_BOOKE_TCR (0x154)
> > +#define SPR_PPE42_TCR (0x154)
> > #define SPR_BOOKE_TLB0PS (0x158)
> > #define SPR_BOOKE_TLB1PS (0x159)
> > #define SPR_BOOKE_TLB2PS (0x15A)
> > @@ -2528,6 +2595,12 @@ enum {
> > PPC2_MEM_LWSYNC = 0x0000000000200000ULL,
> > /* ISA 2.06 BCD assist instructions */
> > PPC2_BCDA_ISA206 = 0x0000000000400000ULL,
> > + /* PPE42 instructions */
> > + PPC2_PPE42 = 0x0000000000800000ULL,
> > + /* PPE42X instructions */
> > + PPC2_PPE42X = 0x0000000001000000ULL,
> > + /* PPE42XM instructions */
> > + PPC2_PPE42XM = 0x0000000002000000ULL,
> >
> > #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \
> > PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
> > @@ -2537,7 +2610,8 @@ enum {
> > PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \
> > PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206 | \
> > PPC2_ISA300 | PPC2_ISA310 | PPC2_MEM_LWSYNC | \
> > - PPC2_BCDA_ISA206)
> > + PPC2_BCDA_ISA206 | PPC2_PPE42 | PPC2_PPE42X | \
> > + PPC2_PPE42XM)
> > };
> >
> > /*****************************************************************************/
> > diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> > index a0e77f2673..698d61bf0c 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)
> > @@ -1679,6 +1720,30 @@ static void init_excp_4xx(CPUPPCState *env)
> > #endif
> > }
> >
> > +static void init_excp_ppe42(CPUPPCState *env)
> > +{
> > +#if !defined(CONFIG_USER_ONLY)
> > + /* Machine Check vector changed after version 0 */
> > + if (((env->spr[SPR_PVR] & 0xf00000ul) >> 20) == 0) {
> > + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000000;
> > + } else {
> > + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000020;
> > + }
> > + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000040;
> > + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000060;
> > + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000080;
> > + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x000000A0;
> > + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x000000C0;
> > + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x000000E0;
> > + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000100;
> > + env->excp_vectors[POWERPC_EXCP_FIT] = 0x00000120;
> > + env->excp_vectors[POWERPC_EXCP_WDT] = 0x00000140;
> > + env->ivpr_mask = 0xFFFFFE00UL;
> > + /* Hardware reset vector */
> > + env->hreset_vector = 0x00000040UL;
> > +#endif
> > +}
> > +
> > static void init_excp_MPC5xx(CPUPPCState *env)
> > {
> > #if !defined(CONFIG_USER_ONLY)
> > @@ -2200,6 +2265,80 @@ POWERPC_FAMILY(405)(ObjectClass *oc, const void *data)
> > POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
> > }
> >
> > +static void init_proc_ppe42(CPUPPCState *env)
> > +{
> > + register_ppe42_sprs(env);
> > +
> > + init_excp_ppe42(env);
> > + env->dcache_line_size = 32;
> > + env->icache_line_size = 32;
> > + /* Allocate hardware IRQ controller */
> > + ppc40x_irq_init(env_archcpu(env));
> > +
> > + SET_FIT_PERIOD(8, 12, 16, 20);
> > + SET_WDT_PERIOD(16, 20, 24, 28);
> > +}
> > +
> > +static void ppe42_class_common_init(PowerPCCPUClass *pcc)
> > +{
> > + pcc->init_proc = init_proc_ppe42;
> > + pcc->check_pow = check_pow_nocheck;
> > + pcc->check_attn = check_attn_none;
> > + pcc->insns_flags = PPC_INSNS_BASE |
> > + PPC_WRTEE |
> > + PPC_CACHE |
> > + PPC_CACHE_DCBZ |
> > + PPC_MEM_SYNC;
> > + pcc->msr_mask = R_MSR_SEM_MASK |
> > + (1ull << MSR_IS0) |
> > + R_MSR_SIBRC_MASK |
> > + (1ull << MSR_LP) |
> > + (1ull << MSR_WE) |
> > + (1ull << MSR_IS1) |
> > + (1ull << MSR_UIE) |
> > + (1ull << MSR_EE) |
> > + (1ull << MSR_ME) |
> > + (1ull << MSR_IS2) |
> > + (1ull << MSR_IS3) |
> > + (1ull << MSR_IPE) |
> > + R_MSR_SIBRCA_MASK;
> > + pcc->mmu_model = POWERPC_MMU_REAL;
> > + pcc->excp_model = POWERPC_EXCP_PPE42;
> > + pcc->bus_model = PPC_FLAGS_INPUT_PPE42;
> > + pcc->bfd_mach = bfd_mach_ppc_403;
> > + pcc->flags = POWERPC_FLAG_PPE42 | POWERPC_FLAG_BUS_CLK;
> > +}
> > +
> > +POWERPC_FAMILY(ppe42)(ObjectClass *oc, const void *data)
> > +{
> > + DeviceClass *dc = DEVICE_CLASS(oc);
> > + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
> > +
> > + dc->desc = "PPE 42";
> > + pcc->insns_flags2 = PPC2_PPE42;
> > + ppe42_class_common_init(pcc);
> > +}
> > +
> > +POWERPC_FAMILY(ppe42x)(ObjectClass *oc, const void *data)
> > +{
> > + DeviceClass *dc = DEVICE_CLASS(oc);
> > + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
> > +
> > + dc->desc = "PPE 42X";
> > + pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X;
> > + ppe42_class_common_init(pcc);
> > +}
> > +
> > +POWERPC_FAMILY(ppe42xm)(ObjectClass *oc, const void *data)
> > +{
> > + DeviceClass *dc = DEVICE_CLASS(oc);
> > + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
> > +
> > + dc->desc = "PPE 42XM";
> > + pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X | PPC2_PPE42XM;
> > + ppe42_class_common_init(pcc);
> > +}
> > +
> > static void init_proc_440EP(CPUPPCState *env)
> > {
> > register_BookE_sprs(env, 0x000000000000FFFFULL);
> > @@ -6802,53 +6941,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 +7016,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 +7397,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)
> > @@ -7725,6 +7880,18 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> > * they can be read with "p $ivor0", "p $ivor1", etc.
> > */
> > break;
> > + case POWERPC_EXCP_PPE42:
> > + qemu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx "\n",
> > + env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
> > +
> > + qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
> > + " ISR " TARGET_FMT_lx " EDR " TARGET_FMT_lx "\n",
> > + env->spr[SPR_PPE42_TCR], env->spr[SPR_PPE42_TSR],
> > + env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
> > +
> > + qemu_fprintf(f, " PIR " TARGET_FMT_lx " IVPR " TARGET_FMT_lx "\n",
> > + env->spr[SPR_PPE42_PIR], env->spr[SPR_PPE42_IVPR]);
> > + break;
> > case POWERPC_EXCP_40x:
> > qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
> > " ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n",
> > diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> > index 1efdc4066e..d8bca19fff 100644
> > --- a/target/ppc/excp_helper.c
> > +++ b/target/ppc/excp_helper.c
> > @@ -949,6 +949,125 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
> > powerpc_set_excp_state(cpu, vector, new_msr);
> > }
> >
> > +static void powerpc_excp_ppe42(PowerPCCPU *cpu, int excp)
> > +{
> > + CPUPPCState *env = &cpu->env;
> > + target_ulong msr, new_msr, vector;
> > + target_ulong mcs = PPE42_ISR_MCS_INSTRUCTION;
> > + bool promote_unmaskable;
> > +
> > + msr = env->msr;
> > +
> > + /*
> > + * New interrupt handler msr preserves SIBRC and ME unless explicitly
> > + * overridden by the exception. All other MSR bits are zeroed out.
> > + */
> > + new_msr = env->msr & (((target_ulong)1 << MSR_ME) | R_MSR_SIBRC_MASK);
> > +
> > + /* HV emu assistance interrupt only exists on server arch 2.05 or later */
> > + if (excp == POWERPC_EXCP_HV_EMU) {
> > + excp = POWERPC_EXCP_PROGRAM;
> > + }
> > +
> > + /*
> > + * Unmaskable interrupts (Program, ISI, Alignment and DSI) are promoted to
> > + * machine check if MSR_UIE is 0.
> > + */
> > + promote_unmaskable = !(msr & ((target_ulong)1 << MSR_UIE));
> > +
> > +
> > + switch (excp) {
> > + case POWERPC_EXCP_MCHECK: /* Machine check exception */
> > + break;
> > + case POWERPC_EXCP_DSI: /* Data storage exception */
> > + trace_ppc_excp_dsi(env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
> > + if (promote_unmaskable) {
> > + excp = POWERPC_EXCP_MCHECK;
> > + mcs = PPE42_ISR_MCS_DSI;
> > + }
> > + break;
> > + case POWERPC_EXCP_ISI: /* Instruction storage exception */
> > + trace_ppc_excp_isi(msr, env->nip);
> > + if (promote_unmaskable) {
> > + excp = POWERPC_EXCP_MCHECK;
> > + mcs = PPE42_ISR_MCS_ISI;
> > + }
> > + break;
> > + case POWERPC_EXCP_EXTERNAL: /* External input */
> > + break;
> > + case POWERPC_EXCP_ALIGN: /* Alignment exception */
> > + if (promote_unmaskable) {
> > + excp = POWERPC_EXCP_MCHECK;
> > + mcs = PPE42_ISR_MCS_ALIGNMENT;
> > + }
> > + break;
> > + case POWERPC_EXCP_PROGRAM: /* Program exception */
> > + if (promote_unmaskable) {
> > + excp = POWERPC_EXCP_MCHECK;
> > + mcs = PPE42_ISR_MCS_PROGRAM;
> > + }
> > + switch (env->error_code & ~0xF) {
> > + case POWERPC_EXCP_INVAL:
> > + trace_ppc_excp_inval(env->nip);
> > + env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_PTR);
> > + break;
> > + case POWERPC_EXCP_TRAP:
> > + env->spr[SPR_PPE42_ISR] |= ((target_ulong)1 << PPE42_ISR_PTR);
> > + break;
> > + default:
> > + /* Should never occur */
> > + cpu_abort(env_cpu(env), "Invalid program exception %d. Aborting\n",
> > + env->error_code);
> > + break;
> > + }
> > +#ifdef CONFIG_TCG
> > + env->spr[SPR_PPE42_EDR] = ppc_ldl_code(env, env->nip);
> > +#endif
> > + break;
> > + case POWERPC_EXCP_DECR: /* Decrementer exception */
> > + break;
> > + case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
> > + trace_ppc_excp_print("FIT");
> > + break;
> > + case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
> > + trace_ppc_excp_print("WDT");
> > + break;
> > + case POWERPC_EXCP_RESET: /* System reset exception */
> > + /* reset exceptions don't have ME set */
> > + new_msr &= ~((target_ulong)1 << MSR_ME);
> > + break;
> > + default:
> > + cpu_abort(env_cpu(env), "Invalid PPE42 exception %d. Aborting\n",
> > + excp);
> > + break;
> > + }
> > +
> > + env->spr[SPR_SRR0] = env->nip;
> > + env->spr[SPR_SRR1] = msr;
> > +
> > + vector = env->excp_vectors[excp];
> > + if (vector == (target_ulong)-1ULL) {
> > + cpu_abort(env_cpu(env),
> > + "Raised an exception without defined vector %d\n", excp);
> > + }
> > + vector |= env->spr[SPR_PPE42_IVPR];
> > +
> > + if (excp == POWERPC_EXCP_MCHECK) {
> > + /* Also set the Machine Check Status (MCS) */
> > + env->spr[SPR_PPE42_ISR] &= ~R_PPE42_ISR_MCS_MASK;
> > + env->spr[SPR_PPE42_ISR] |= (mcs & R_PPE42_ISR_MCS_MASK);
> > + env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_MFE);
> > +
> > + /* Machine checks halt execution if MSR_ME is 0 */
> > + powerpc_mcheck_checkstop(env);
> > +
> > + /* machine check exceptions don't have ME set */
> > + new_msr &= ~((target_ulong)1 << MSR_ME);
> > + }
> > +
> > + powerpc_set_excp_state(cpu, vector, new_msr);
> > +}
> > +
> > static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
> > {
> > CPUPPCState *env = &cpu->env;
> > @@ -1589,6 +1708,9 @@ void powerpc_excp(PowerPCCPU *cpu, int excp)
> > case POWERPC_EXCP_POWER11:
> > powerpc_excp_books(cpu, excp);
> > break;
> > + case POWERPC_EXCP_PPE42:
> > + powerpc_excp_ppe42(cpu, excp);
> > + break;
> > default:
> > g_assert_not_reached();
> > }
> > @@ -1945,6 +2067,43 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env,
> > }
> > #endif /* TARGET_PPC64 */
> >
> > +static int ppe42_next_unmasked_interrupt(CPUPPCState *env)
> > +{
> > + bool async_deliver;
> > +
> > + /* External reset */
> > + if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
> > + return PPC_INTERRUPT_RESET;
> > + }
> > + /* Machine check exception */
> > + if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
> > + return PPC_INTERRUPT_MCK;
> > + }
> > +
> > + async_deliver = FIELD_EX64(env->msr, MSR, EE);
> > +
> > + if (async_deliver != 0) {
> > + /* Watchdog timer */
> > + if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
> > + return PPC_INTERRUPT_WDT;
> > + }
> > + /* External Interrupt */
> > + if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
> > + return PPC_INTERRUPT_EXT;
> > + }
> > + /* Fixed interval timer */
> > + if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
> > + return PPC_INTERRUPT_FIT;
> > + }
> > + /* Decrementer exception */
> > + if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
> > + return PPC_INTERRUPT_DECR;
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > static int ppc_next_unmasked_interrupt(CPUPPCState *env)
> > {
> > uint32_t pending_interrupts = env->pending_interrupts;
> > @@ -1970,6 +2129,10 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
> > }
> > #endif
> >
> > + if (env->excp_model == POWERPC_EXCP_PPE42) {
> > + return ppe42_next_unmasked_interrupt(env);
> > + }
> > +
> > /* External reset */
> > if (pending_interrupts & PPC_INTERRUPT_RESET) {
> > return PPC_INTERRUPT_RESET;
> > diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
> > index 7e5726871e..9953d73884 100644
> > --- a/target/ppc/helper_regs.c
> > +++ b/target/ppc/helper_regs.c
> > @@ -186,6 +186,10 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
> > if (env->spr[SPR_LPCR] & LPCR_HR) {
> > hflags |= 1 << HFLAGS_HR;
> > }
> > + if (unlikely(ppc_flags & POWERPC_FLAG_PPE42)) {
> > + /* PPE42 has a single address space and no problem state */
> > + msr = 0;
> > + }
> >
> > #ifndef CONFIG_USER_ONLY
> > if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
> > @@ -306,9 +310,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)) {
> > @@ -319,8 +320,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 MSR has bits overlapping with others */
> > + if (!(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
> > @@ -462,6 +469,17 @@ void register_generic_sprs(PowerPCCPU *cpu)
> > SPR_NOACCESS, SPR_NOACCESS,
> > &spr_read_generic, &spr_write_generic,
> > 0x00000000);
> > +
> > + if (env->insns_flags2 & PPC2_PPE42) {
> > + spr_register(env, SPR_PVR, "PVR",
> > + SPR_NOACCESS, SPR_NOACCESS,
> > + &spr_read_generic, SPR_NOACCESS,
> > + pcc->pvr);
> > +
> > + /* PPE42 doesn't support additional SPRG regs or timebase */
> > + return;
> > + }
> > +
> > spr_register(env, SPR_SPRG1, "SPRG1",
> > SPR_NOACCESS, SPR_NOACCESS,
> > &spr_read_generic, &spr_write_generic,
> > diff --git a/target/ppc/tcg-excp_helper.c b/target/ppc/tcg-excp_helper.c
> > index f835be5156..edecfb8572 100644
> > --- a/target/ppc/tcg-excp_helper.c
> > +++ b/target/ppc/tcg-excp_helper.c
> > @@ -229,6 +229,18 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
> > case POWERPC_MMU_BOOKE206:
> > env->spr[SPR_BOOKE_DEAR] = vaddr;
> > break;
> > + case POWERPC_MMU_REAL:
> > + if (env->flags & POWERPC_FLAG_PPE42) {
> > + env->spr[SPR_PPE42_EDR] = vaddr;
> > + if (access_type == MMU_DATA_STORE) {
> > + env->spr[SPR_PPE42_ISR] |= PPE42_ISR_ST;
> > + } else {
> > + env->spr[SPR_PPE42_ISR] &= ~PPE42_ISR_ST;
> > + }
> > + } else {
> > + env->spr[SPR_DAR] = vaddr;
> > + }
> > + break;
> > default:
> > env->spr[SPR_DAR] = vaddr;
> > break;
> > 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
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 3/4] hw/ppc: Add a test machine for the IBM PPE42 CPU
2025-09-02 16:56 ` Miles Glenn
@ 2025-09-03 22:50 ` Miles Glenn
0 siblings, 0 replies; 14+ messages in thread
From: Miles Glenn @ 2025-09-03 22:50 UTC (permalink / raw)
To: Cédric Le Goater, qemu-devel
Cc: qemu-ppc, npiggin, harshpb, thuth, rathc, richard.henderson
On Tue, 2025-09-02 at 11:56 -0500, Miles Glenn wrote:
> > > +
> > > +static void main_cpu_reset(void *opaque)
> > > +{
> > > + PowerPCCPU *cpu = opaque;
> > > +
> > > + cpu_reset(CPU(cpu));
> >
> > There are no register settings ? Just asking
> >
>
> Admittedly, I did not do much digging into the reset case. I'll look
> into it.
Cédric,
As far as I can tell, it doesn't look like we need to add any other
registers here besides the cpu registers, which are already handled by
cpu_reset(). Also, I did verify that executing a system_reset from the
QEMU command line works as expected (resets to the correct vector and
executes successfully).
Thanks,
Glenn
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 2/4] target/ppc: Add IBM PPE42 special instructions
2025-08-26 20:17 ` [PATCH v2 2/4] target/ppc: Add IBM PPE42 special instructions Glenn Miles
@ 2025-09-04 12:24 ` Chinmay Rath
2025-09-04 12:30 ` Chinmay Rath
1 sibling, 0 replies; 14+ messages in thread
From: Chinmay Rath @ 2025-09-04 12:24 UTC (permalink / raw)
To: Glenn Miles, qemu-devel
Cc: qemu-ppc, clg, npiggin, harshpb, thuth, richard.henderson
On 8/27/25 01:47, Glenn Miles wrote:
> Adds the following instructions exclusively for
> IBM PPE42 processors:
>
> LSKU
> LCXU
> STSKU
> STCXU
> LVD
> LVDU
> LVDX
> STVD
> STVDU
> STVDX
> SLVD
> SRVD
> CMPWBC
> CMPLWBC
> CMPWIBC
> BNBWI
> BNBW
> CLRBWIBC
> CLRWBC
> DCBQ
> RLDICL
> RLDICR
> RLDIMI
>
> A PPE42 GCC compiler is available here:
> https://github.com/open-power/ppe42-gcc
>
> For more information on the PPE42 processors please visit:
> https://wiki.raptorcs.com/w/images/a/a3/PPE_42X_Core_Users_Manual.pdf
>
> Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
> ---
> target/ppc/insn32.decode | 66 ++-
> target/ppc/translate.c | 29 +-
> target/ppc/translate/ppe-impl.c.inc | 805 ++++++++++++++++++++++++++++
> 3 files changed, 890 insertions(+), 10 deletions(-)
> create mode 100644 target/ppc/translate/ppe-impl.c.inc
>
> diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
> index e53fd2840d..8beb588a2a 100644
> --- a/target/ppc/insn32.decode
> +++ b/target/ppc/insn32.decode
> @@ -58,6 +58,10 @@
> %ds_rtp 22:4 !function=times_2
> @DS_rtp ...... ....0 ra:5 .............. .. &D rt=%ds_rtp si=%ds_si
>
> +%dd_si 3:s13
> +&DD rt ra si:int64_t
> +@DD ...... rt:5 ra:5 ............. . .. &DD si=%dd_si
> +
> &DX_b vrt b
> %dx_b 6:10 16:5 0:1
> @DX_b ...... vrt:5 ..... .......... ..... . &DX_b b=%dx_b
> @@ -66,6 +70,11 @@
> %dx_d 6:s10 16:5 0:1
> @DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d
>
> +%md_sh 1:1 11:5
> +%md_mb 5:1 6:5
> +&MD rs ra sh mb rc
> +@MD ...... rs:5 ra:5 ..... ...... ... . rc:1 &MD sh=%md_sh mb=%md_mb
> +
> &VA vrt vra vrb rc
> @VA ...... vrt:5 vra:5 vrb:5 rc:5 ...... &VA
>
> @@ -322,6 +331,13 @@ LDUX 011111 ..... ..... ..... 0000110101 - @X
>
> LQ 111000 ..... ..... ............ ---- @DQ_rtp
>
> +LVD 000101 ..... ..... ................ @D
> +LVDU 001001 ..... ..... ................ @D
> +LVDX 011111 ..... ..... ..... 0000010001 - @X
> +LSKU 111010 ..... ..... ............. 0 11 @DD
> +LCXU 111010 ..... ..... ............. 1 11 @DD
> +
> +
> ### Fixed-Point Store Instructions
>
> STB 100110 ..... ..... ................ @D
> @@ -346,6 +362,11 @@ STDUX 011111 ..... ..... ..... 0010110101 - @X
>
> STQ 111110 ..... ..... ..............10 @DS_rtp
>
> +STVDU 010110 ..... ..... ................ @D
> +STVDX 011111 ..... ..... ..... 0010010001 - @X
> +STSKU 111110 ..... ..... ............. 0 11 @DD
> +STCXU 111110 ..... ..... ............. 1 11 @DD
> +
> ### Fixed-Point Compare Instructions
>
> CMP 011111 ... - . ..... ..... 0000000000 - @X_bfl
> @@ -461,8 +482,14 @@ PRTYD 011111 ..... ..... ----- 0010111010 - @X_sa
>
> BPERMD 011111 ..... ..... ..... 0011111100 - @X
> CFUGED 011111 ..... ..... ..... 0011011100 - @X
> -CNTLZDM 011111 ..... ..... ..... 0000111011 - @X
> -CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
> +{
> + SLVD 011111 ..... ..... ..... 0000111011 . @X_rc
> + CNTLZDM 011111 ..... ..... ..... 0000111011 - @X
> +}
> +{
> + SRVD 011111 ..... ..... ..... 1000111011 . @X_rc
> + CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
> +}
> PDEPD 011111 ..... ..... ..... 0010011100 - @X
> PEXTD 011111 ..... ..... ..... 0010111100 - @X
>
> @@ -981,8 +1008,16 @@ LXSSP 111001 ..... ..... .............. 11 @DS
> STXSSP 111101 ..... ..... .............. 11 @DS
> LXV 111101 ..... ..... ............ . 001 @DQ_TSX
> STXV 111101 ..... ..... ............ . 101 @DQ_TSX
> -LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP
> -STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP
> +
> +# STVD PPE instruction overlaps with the LXVP and STXVP instructions
> +{
> + STVD 000110 ..... ..... ................ @D
> + [
> + LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP
> + STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP
> + ]
> +}
> +
> LXVX 011111 ..... ..... ..... 0100 - 01100 . @X_TSX
> STXVX 011111 ..... ..... ..... 0110001100 . @X_TSX
> LXVPX 011111 ..... ..... ..... 0101001101 - @X_TSXP
> @@ -1300,3 +1335,26 @@ CLRBHRB 011111 ----- ----- ----- 0110101110 -
> ## Misc POWER instructions
>
> ATTN 000000 00000 00000 00000 0100000000 0
> +
> +# Fused compare-branch instructions for PPE only
> +%fcb_bdx 1:s10 !function=times_4
> +&FCB px:bool ra rb:uint64_t bdx lk:bool
> +@FCB ...... .. px:1 .. ra:5 rb:5 .......... lk:1 &FCB bdx=%fcb_bdx
> +&FCB_bix px:bool bix ra rb:uint64_t bdx lk:bool
> +@FCB_bix ...... .. px:1 bix:2 ra:5 rb:5 .......... lk:1 &FCB_bix bdx=%fcb_bdx
> +
> +CMPWBC 000001 00 . .. ..... ..... .......... . @FCB_bix
> +CMPLWBC 000001 01 . .. ..... ..... .......... . @FCB_bix
> +CMPWIBC 000001 10 . .. ..... ..... .......... . @FCB_bix
> +BNBWI 000001 11 . 00 ..... ..... .......... . @FCB
> +BNBW 000001 11 . 01 ..... ..... .......... . @FCB
> +CLRBWIBC 000001 11 . 10 ..... ..... .......... . @FCB
> +CLRBWBC 000001 11 . 11 ..... ..... .......... . @FCB
> +
> +# Data Cache Block Query for PPE only
> +DCBQ 011111 ..... ..... ..... 0110010110 - @X
> +
> +# Rotate Doubleword Instructions for PPE only (if TARGET_PPC64 not defined)
> +RLDICL 011110 ..... ..... ..... ...... 000 . . @MD
> +RLDICR 011110 ..... ..... ..... ...... 001 . . @MD
> +RLDIMI 011110 ..... ..... ..... ...... 011 . . @MD
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index fc817dab54..d422789a1d 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -209,6 +209,11 @@ struct DisasContext {
> #define DISAS_CHAIN DISAS_TARGET_2 /* lookup next tb, pc updated */
> #define DISAS_CHAIN_UPDATE DISAS_TARGET_3 /* lookup next tb, pc stale */
>
> +static inline bool is_ppe(const DisasContext *ctx)
> +{
> + return !!(ctx->flags & POWERPC_FLAG_PPE42);
> +}
> +
> /* Return true iff byteswap is needed in a scalar memop */
> static inline bool need_byteswap(const DisasContext *ctx)
> {
> @@ -556,11 +561,8 @@ void spr_access_nop(DisasContext *ctx, int sprn, int gprn)
>
> #endif
>
> -/* SPR common to all PowerPC */
> -/* XER */
> -void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
> +static void gen_get_xer(DisasContext *ctx, TCGv dst)
> {
> - TCGv dst = cpu_gpr[gprn];
> TCGv t0 = tcg_temp_new();
> TCGv t1 = tcg_temp_new();
> TCGv t2 = tcg_temp_new();
> @@ -579,9 +581,16 @@ void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
> }
> }
>
> -void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
> +/* SPR common to all PowerPC */
> +/* XER */
> +void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
> +{
> + TCGv dst = cpu_gpr[gprn];
> + gen_get_xer(ctx, dst);
> +}
> +
> +static void gen_set_xer(DisasContext *ctx, TCGv src)
> {
> - TCGv src = cpu_gpr[gprn];
> /* Write all flags, while reading back check for isa300 */
> tcg_gen_andi_tl(cpu_xer, src,
> ~((1u << XER_SO) |
> @@ -594,6 +603,12 @@ void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
> tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1);
> }
>
> +void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
> +{
> + TCGv src = cpu_gpr[gprn];
> + gen_set_xer(ctx, src);
> +}
> +
> /* LR */
> void spr_read_lr(DisasContext *ctx, int gprn, int sprn)
> {
> @@ -5755,6 +5770,8 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a)
>
> #include "translate/bhrb-impl.c.inc"
>
> +#include "translate/ppe-impl.c.inc"
> +
> /* Handles lfdp */
> static void gen_dform39(DisasContext *ctx)
> {
> diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ppe-impl.c.inc
> new file mode 100644
> index 0000000000..98fd794aa4
> --- /dev/null
> +++ b/target/ppc/translate/ppe-impl.c.inc
> @@ -0,0 +1,805 @@
> +/*
> + * IBM PPE Instructions
> + *
> + * Copyright (c) 2024, IBM Corporation.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +
> +#if !defined(TARGET_PPC64)
> +static bool vdr_is_valid(uint32_t vdr)
> +{
> + const uint32_t valid_bitmap = 0xf00003ff;
> + return !!((1ul << (vdr & 0x1f)) & valid_bitmap);
> +}
> +
> +static bool ppe_gpr_is_valid(uint32_t reg)
> +{
> + const uint32_t valid_bitmap = 0xf00027ff;
> + return !!((1ul << (reg & 0x1f)) & valid_bitmap);
> +}
> +#endif
> +
> +#define CHECK_VDR(CTX, VDR) \
> + do { \
> + if (unlikely(!vdr_is_valid(VDR))) { \
> + gen_invalid(CTX); \
> + return true; \
> + } \
> + } while (0)
> +
> +#define CHECK_PPE_GPR(CTX, REG) \
> + do { \
> + if (unlikely(!ppe_gpr_is_valid(REG))) { \
> + gen_invalid(CTX); \
> + return true; \
> + } \
> + } while (0)
> +
> +#define CHECK_VDR(CTX, VDR) \
> + do { \
> + if (unlikely(!vdr_is_valid(VDR))) { \
> + gen_invalid(CTX); \
> + return true; \
> + } \
> + } while (0)
> +
> +#define VDR_PAIR_REG(VDR) (((VDR) + 1) & 0x1f)
> +
> +#define CHECK_PPE_LEVEL(CTX, LVL) \
> + do { \
> + if (unlikely(!((CTX)->insns_flags2 & (LVL)))) { \
> + gen_invalid(CTX); \
> + return true; \
> + } \
> + } while (0)
> +
> +static bool trans_LCXU(DisasContext *ctx, arg_LCXU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + int i;
> + TCGv base, EA;
> + TCGv lo, hi;
> + TCGv_i64 t8;
> + const uint8_t vd_list[] = {9, 7, 5, 3, 0};
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_PPE_GPR(ctx, a->rt);
> +
> + if (unlikely((a->rt != a->ra) || (a->ra == 0) || (a->si < 0xB))) {
> + gen_invalid(ctx);
> + return true;
> + }
> +
> + EA = tcg_temp_new();
> + base = tcg_temp_new();
> +
> + tcg_gen_addi_tl(base, cpu_gpr[a->ra], a->si * 8);
> + gen_store_spr(SPR_PPE42_EDR, base);
> +
> + t8 = tcg_temp_new_i64();
> +
> + tcg_gen_addi_tl(EA, base, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(cpu_gpr[31], cpu_gpr[30], t8);
> +
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(cpu_gpr[29], cpu_gpr[28], t8);
> +
> + lo = tcg_temp_new();
> + hi = tcg_temp_new();
> +
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(lo, hi, t8);
> + gen_store_spr(SPR_SRR0, hi);
> + gen_store_spr(SPR_SRR1, lo);
> +
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(lo, hi, t8);
> + gen_set_xer(ctx, hi);
> + tcg_gen_mov_tl(cpu_ctr, lo);
> +
> + for (i = 0; i < sizeof(vd_list); i++) {
> + int vd = vd_list[i];
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd], t8);
> + }
> +
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(lo, hi, t8);
> + tcg_gen_shri_tl(hi, hi, 28);
> + tcg_gen_trunc_tl_i32(cpu_crf[0], hi);
> + gen_store_spr(SPR_SPRG0, lo);
> +
> + tcg_gen_addi_tl(EA, base, 4);
> + tcg_gen_qemu_ld_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> + tcg_gen_mov_tl(cpu_gpr[a->ra], base);
> + return true;
> +#endif
> +}
> +
> +static bool trans_LSKU(DisasContext *ctx, arg_LSKU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + int64_t n;
> + TCGv base, EA;
> + TCGv_i32 lo, hi;
> + TCGv_i64 t8;
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> +
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_PPE_GPR(ctx, a->rt);
> +
> + if (unlikely((a->rt != a->ra) || (a->ra == 0) ||
> + (a->si & PPC_BIT(0)) || (a->si == 0))) {
> + gen_invalid(ctx);
> + return true;
> + }
> +
> + EA = tcg_temp_new();
> + base = tcg_temp_new();
> + gen_addr_register(ctx, base);
> +
> +
> + tcg_gen_addi_tl(base, base, a->si * 8);
> + gen_store_spr(SPR_PPE42_EDR, base);
> +
> + n = a->si - 1;
> + t8 = tcg_temp_new_i64();
> + if (n > 0) {
> + tcg_gen_addi_tl(EA, base, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + hi = cpu_gpr[30];
> + lo = cpu_gpr[31];
> + tcg_gen_extr_i64_i32(lo, hi, t8);
> + }
> + if (n > 1) {
> + tcg_gen_addi_tl(EA, base, -16);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + hi = cpu_gpr[28];
> + lo = cpu_gpr[29];
> + tcg_gen_extr_i64_i32(lo, hi, t8);
> + }
> + tcg_gen_addi_tl(EA, base, 4);
> + tcg_gen_qemu_ld_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> + tcg_gen_mov_tl(cpu_gpr[a->ra], base);
> + return true;
> +#endif
> +}
> +
> +static bool trans_STCXU(DisasContext *ctx, arg_STCXU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + TCGv EA;
> + TCGv lo, hi;
> + TCGv_i64 t8;
> + int i;
> + const uint8_t vd_list[] = {9, 7, 5, 3, 0};
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> +
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_PPE_GPR(ctx, a->rt);
> +
> + if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) {
> + gen_invalid(ctx);
> + return true;
> + }
> +
> + EA = tcg_temp_new();
> + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], 4);
> + tcg_gen_qemu_st_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> +
> + gen_store_spr(SPR_PPE42_EDR, cpu_gpr[a->ra]);
> +
> + t8 = tcg_temp_new_i64();
> +
> + tcg_gen_concat_tl_i64(t8, cpu_gpr[31], cpu_gpr[30]);
> + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> +
> + tcg_gen_concat_tl_i64(t8, cpu_gpr[29], cpu_gpr[28]);
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> +
> + lo = tcg_temp_new();
> + hi = tcg_temp_new();
> +
> + gen_load_spr(hi, SPR_SRR0);
> + gen_load_spr(lo, SPR_SRR1);
> + tcg_gen_concat_tl_i64(t8, lo, hi);
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> +
> + gen_get_xer(ctx, hi);
> + tcg_gen_mov_tl(lo, cpu_ctr);
> + tcg_gen_concat_tl_i64(t8, lo, hi);
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> +
> + for (i = 0; i < sizeof(vd_list); i++) {
> + int vd = vd_list[i];
> + tcg_gen_concat_tl_i64(t8, cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd]);
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + }
> +
> + gen_load_spr(lo, SPR_SPRG0);
> + tcg_gen_extu_i32_tl(hi, cpu_crf[0]);
> + tcg_gen_shli_tl(hi, hi, 28);
> + tcg_gen_concat_tl_i64(t8, lo, hi);
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> +
> + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], a->si * 8);
> + tcg_gen_qemu_st_i32(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) |
> + MO_ALIGN);
> + tcg_gen_mov_tl(cpu_gpr[a->ra], EA);
> + return true;
> +#endif
> +}
> +
> +static bool trans_STSKU(DisasContext *ctx, arg_STSKU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + int64_t n;
> + TCGv base, EA;
> + TCGv_i32 lo, hi;
> + TCGv_i64 t8;
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> +
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_PPE_GPR(ctx, a->rt);
> +
> + if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) {
> + gen_invalid(ctx);
> + return true;
> + }
> +
> + EA = tcg_temp_new();
> + base = tcg_temp_new();
> + gen_addr_register(ctx, base);
> + tcg_gen_addi_tl(EA, base, 4);
> + tcg_gen_qemu_st_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> +
> + gen_store_spr(SPR_PPE42_EDR, base);
> +
> + n = ~(a->si);
> +
> + t8 = tcg_temp_new_i64();
> + if (n > 0) {
> + hi = cpu_gpr[30];
> + lo = cpu_gpr[31];
> + tcg_gen_concat_i32_i64(t8, lo, hi);
> + tcg_gen_addi_tl(EA, base, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + }
> + if (n > 1) {
> + hi = cpu_gpr[28];
> + lo = cpu_gpr[29];
> + tcg_gen_concat_i32_i64(t8, lo, hi);
> + tcg_gen_addi_tl(EA, base, -16);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + }
> +
> + tcg_gen_addi_tl(EA, base, a->si * 8);
> + tcg_gen_qemu_st_i32(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) |
> + MO_ALIGN);
> + tcg_gen_mov_tl(cpu_gpr[a->ra], EA);
> + return true;
> +#endif
> +}
> +
> +#if !defined(TARGET_PPC64)
> +static bool do_ppe_ldst(DisasContext *ctx, int rt, int ra, TCGv displ,
> + bool update, bool store)
> +{
> + TCGv ea;
> + int rt_lo;
> + TCGv_i64 t8;
> +
> + CHECK_VDR(ctx, rt);
> + CHECK_PPE_GPR(ctx, ra);
> + rt_lo = VDR_PAIR_REG(rt);
> + if (update && (ra == 0 || (!store && ((ra == rt) || (ra == rt_lo))))) {
> + gen_invalid(ctx);
> + return true;
> + }
> + gen_set_access_type(ctx, ACCESS_INT);
> +
> + ea = do_ea_calc(ctx, ra, displ);
> + t8 = tcg_temp_new_i64();
> + if (store) {
> + tcg_gen_concat_i32_i64(t8, cpu_gpr[rt_lo], cpu_gpr[rt]);
> + tcg_gen_qemu_st_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64));
> + } else {
> + tcg_gen_qemu_ld_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64));
> + tcg_gen_extr_i64_i32(cpu_gpr[rt_lo], cpu_gpr[rt], t8);
> + }
> + if (update) {
> + tcg_gen_mov_tl(cpu_gpr[ra], ea);
> + }
> + return true;
> +}
> +#endif
> +
> +static bool trans_LVD(DisasContext *ctx, arg_LVD *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), false, false);
> +#endif
> +}
> +
> +static bool trans_LVDU(DisasContext *ctx, arg_LVDU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), true, false);
> +#endif
> +}
> +
> +static bool trans_LVDX(DisasContext *ctx, arg_LVDX *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, false);
> +#endif
> +}
> +
> +static bool trans_STVD(DisasContext *ctx, arg_STVD *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), false, true);
> +#endif
> +}
> +
> +static bool trans_STVDU(DisasContext *ctx, arg_STVDU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), true, true);
> +#endif
> +}
> +
> +static bool trans_STVDX(DisasContext *ctx, arg_STVDX *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, true);
> +#endif
> +}
> +
> +#if !defined(TARGET_PPC64)
> +static bool do_fcb(DisasContext *ctx, TCGv ra_val, TCGv rb_val, int bix,
> + int32_t bdx, bool s, bool px, bool lk)
> +{
> + TCGCond cond;
> + uint32_t mask;
> + TCGLabel *no_branch;
> + target_ulong dest;
> +
> + /* Update CR0 */
> + gen_op_cmp32(ra_val, rb_val, s, 0);
> +
> + if (lk) {
> + gen_setlr(ctx, ctx->base.pc_next);
> + }
> +
> +
> + mask = PPC_BIT32(28 + bix);
> + cond = (px) ? TCG_COND_TSTEQ : TCG_COND_TSTNE;
> + no_branch = gen_new_label();
> + dest = ctx->cia + bdx;
> +
> + /* Do the branch if CR0[bix] == PX */
> + tcg_gen_brcondi_i32(cond, cpu_crf[0], mask, no_branch);
> + gen_goto_tb(ctx, 0, dest);
> + gen_set_label(no_branch);
> + gen_goto_tb(ctx, 1, ctx->base.pc_next);
> + ctx->base.is_jmp = DISAS_NORETURN;
> + return true;
> +}
> +#endif
> +
> +#if !defined(TARGET_PPC64)
> +static bool do_cmp_branch(DisasContext *ctx, int ra, TCGv rb_val, int bix,
> + int32_t bdx, bool s, bool px, bool lk)
> +{
> + TCGv old_ra;
> +
> + CHECK_PPE_GPR(ctx, ra);
> + if (bix == 3) {
> + old_ra = tcg_temp_new();
> + tcg_gen_mov_tl(old_ra, cpu_gpr[ra]);
> + tcg_gen_sub_tl(cpu_gpr[ra], cpu_gpr[ra], rb_val);
> + return do_fcb(ctx, old_ra, rb_val, 2,
> + bdx, s, px, lk);
> + } else {
> + return do_fcb(ctx, cpu_gpr[ra], rb_val, bix,
> + bdx, s, px, lk);
> + }
> +}
> +#endif
> +
> +#if !defined(TARGET_PPC64)
> +static bool do_mask_branch(DisasContext *ctx, int ra, TCGv mask,
> + int32_t bdx, bool invert, bool px, bool lk,
> + bool update)
> +{
> + TCGv r;
> + CHECK_PPE_GPR(ctx, ra);
> + if (invert) {
> + tcg_gen_not_tl(mask, mask);
> + }
> +
> + /* apply mask to ra */
> + r = tcg_temp_new();
> + tcg_gen_and_tl(r, cpu_gpr[ra], mask);
> + if (update) {
> + tcg_gen_mov_tl(cpu_gpr[ra], r);
> + }
> + return do_fcb(ctx, r, tcg_constant_tl(0), 2,
> + bdx, false, px, lk);
> +}
> +#endif
> +
> +static bool trans_CMPWBC(DisasContext *ctx, arg_CMPWBC *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + return do_cmp_branch(ctx, a->ra, cpu_gpr[a->rb], a->bix, a->bdx,
> + true, a->px, a->lk);
> +#endif
> +}
> +
> +static bool trans_CMPLWBC(DisasContext *ctx, arg_CMPLWBC *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + return do_cmp_branch(ctx, a->ra, cpu_gpr[a->rb], a->bix, a->bdx,
> + false, a->px, a->lk);
> +#endif
> +}
> +
> +static bool trans_CMPWIBC(DisasContext *ctx, arg_CMPWIBC *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_cmp_branch(ctx, a->ra, tcg_constant_tl(a->rb), a->bix, a->bdx,
> + true, a->px, a->lk);
> +#endif
> +}
> +
> +static bool trans_BNBWI(DisasContext *ctx, arg_BNBWI *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_mask_branch(ctx, a->ra, tcg_constant_tl(PPC_BIT32(a->rb)),
> + a->bdx, false, a->px, a->lk, false);
> +#endif
> +}
> +
> +static bool trans_BNBW(DisasContext *ctx, arg_BNBW *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + TCGv mask, shift;
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + mask = tcg_temp_new();
> + shift = tcg_temp_new();
> + tcg_gen_andi_tl(shift, cpu_gpr[a->rb], 0x1f);
> + tcg_gen_shr_tl(mask, tcg_constant_tl(0x80000000), shift);
> + return do_mask_branch(ctx, a->ra, mask, a->bdx, false, a->px, a->lk, false);
> +#endif
> +}
> +
> +static bool trans_CLRBWIBC(DisasContext *ctx, arg_CLRBWIBC *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_mask_branch(ctx, a->ra, tcg_constant_tl(PPC_BIT32(a->rb)),
> + a->bdx, true, a->px, a->lk, true);
> +#endif
> +}
> +
> +static bool trans_CLRBWBC(DisasContext *ctx, arg_CLRBWBC *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + TCGv mask, shift;
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + mask = tcg_temp_new();
> + shift = tcg_temp_new();
> + tcg_gen_andi_tl(shift, cpu_gpr[a->rb], 0x1f);
> + tcg_gen_shr_tl(mask, tcg_constant_tl(0x80000000), shift);
> + return do_mask_branch(ctx, a->ra, mask, a->bdx, true, a->px, a->lk, true);
> +#endif
> +}
> +
> +#if !defined(TARGET_PPC64)
> +static void gen_set_Rc0_i64(DisasContext *ctx, TCGv_i64 reg)
> +{
> + TCGv_i64 t0 = tcg_temp_new_i64();
> + TCGv_i64 t1 = tcg_temp_new_i64();
> + TCGv_i32 t = tcg_temp_new_i32();
> +
> + tcg_gen_movi_i64(t0, CRF_EQ);
> + tcg_gen_movi_i64(t1, CRF_LT);
> + tcg_gen_movcond_i64(TCG_COND_LT, t0, reg, tcg_constant_i64(0), t1, t0);
> + tcg_gen_movi_i64(t1, CRF_GT);
> + tcg_gen_movcond_i64(TCG_COND_GT, t0, reg, tcg_constant_i64(0), t1, t0);
> + tcg_gen_extrl_i64_i32(t, t0);
> + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
> + tcg_gen_or_i32(cpu_crf[0], cpu_crf[0], t);
> +}
> +#endif
> +
> +#if !defined(TARGET_PPC64)
> +static bool do_shift64(DisasContext *ctx, arg_X_rc *a, bool left)
> +{
> + int rt_lo, ra_lo;
> + TCGv_i64 t0, t8;
> +
> + /* Check for PPE since opcode overlaps with CNTTZDM instruction */
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_VDR(ctx, a->rt);
> + CHECK_VDR(ctx, a->ra);
> + CHECK_PPE_GPR(ctx, a->rb);
> + rt_lo = VDR_PAIR_REG(a->rt);
> + ra_lo = VDR_PAIR_REG(a->ra);
> + t8 = tcg_temp_new_i64();
> +
> + /* AND rt with a mask that is 0 when rb >= 0x40 */
> + t0 = tcg_temp_new_i64();
> + tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]);
> + tcg_gen_shli_i64(t0, t0, 0x39);
> + tcg_gen_sari_i64(t0, t0, 0x3f);
> +
> + /* form 64bit value from two 32bit regs */
> + tcg_gen_concat_tl_i64(t8, cpu_gpr[rt_lo], cpu_gpr[a->rt]);
> +
> + /* apply mask */
> + tcg_gen_andc_i64(t8, t8, t0);
> +
> + /* do the shift */
> + tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]);
> + tcg_gen_andi_i64(t0, t0, 0x3f);
> + if (left) {
> + tcg_gen_shl_i64(t8, t8, t0);
> + } else {
> + tcg_gen_shr_i64(t8, t8, t0);
> + }
> +
> + /* split the 64bit word back into two 32bit regs */
> + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8);
> +
> + /* update CR0 if requested */
> + if (unlikely(a->rc != 0)) {
> + gen_set_Rc0_i64(ctx, t8);
> + }
> + return true;
> +}
> +#endif
> +
> +static bool trans_SRVD(DisasContext *ctx, arg_SRVD *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + return do_shift64(ctx, a, false);
> +#endif
> +}
> +
> +static bool trans_SLVD(DisasContext *ctx, arg_SLVD *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + return do_shift64(ctx, a, true);
> +#endif
> +}
> +
> +static bool trans_DCBQ(DisasContext *ctx, arg_DCBQ *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> +
> + CHECK_PPE_GPR(ctx, a->rt);
> + CHECK_PPE_GPR(ctx, a->ra);
> + CHECK_PPE_GPR(ctx, a->rb);
> +
> + /* No cache exists, so just set RT to 0 */
> + tcg_gen_movi_tl(cpu_gpr[a->rt], 0);
> + return true;
> +#endif
> +}
> +
> +static bool trans_RLDIMI(DisasContext *ctx, arg_RLDIMI *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + TCGv_i64 t_rs, t_ra;
> + int ra_lo, rs_lo;
> + uint32_t sh = a->sh;
> + uint32_t mb = a->mb;
> + uint32_t me = 63 - sh;
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_VDR(ctx, a->rs);
> + CHECK_VDR(ctx, a->ra);
> +
> + rs_lo = VDR_PAIR_REG(a->rs);
> + ra_lo = VDR_PAIR_REG(a->ra);
> +
> + t_rs = tcg_temp_new_i64();
> + t_ra = tcg_temp_new_i64();
> +
> + tcg_gen_concat_tl_i64(t_rs, cpu_gpr[rs_lo], cpu_gpr[a->rs]);
> + tcg_gen_concat_tl_i64(t_ra, cpu_gpr[ra_lo], cpu_gpr[a->ra]);
> +
> + if (mb <= me) {
> + tcg_gen_deposit_i64(t_ra, t_ra, t_rs, sh, me - mb + 1);
> + } else {
> + uint64_t mask = mask_u64(mb, me);
> + TCGv_i64 t1 = tcg_temp_new_i64();
> +
> + tcg_gen_rotli_i64(t1, t_rs, sh);
> + tcg_gen_andi_i64(t1, t1, mask);
> + tcg_gen_andi_i64(t_ra, t_ra, ~mask);
> + tcg_gen_or_i64(t_ra, t_ra, t1);
> + }
> +
> + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t_ra);
> +
> + if (unlikely(a->rc != 0)) {
> + gen_set_Rc0_i64(ctx, t_ra);
> + }
> + return true;
> +#endif
> +}
> +
> +
> +#if !defined(TARGET_PPC64)
> +static bool gen_rldinm_i64(DisasContext *ctx, arg_MD *a, int mb, int me, int sh)
> +{
> + int len = me - mb + 1;
> + int rsh = (64 - sh) & 63;
> + int ra_lo, rs_lo;
> + TCGv_i64 t8;
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_VDR(ctx, a->rs);
> + CHECK_VDR(ctx, a->ra);
> +
> + rs_lo = VDR_PAIR_REG(a->rs);
> + ra_lo = VDR_PAIR_REG(a->ra);
> + t8 = tcg_temp_new_i64();
> + tcg_gen_concat_tl_i64(t8, cpu_gpr[rs_lo], cpu_gpr[a->rs]);
> + if (sh != 0 && len > 0 && me == (63 - sh)) {
> + tcg_gen_deposit_z_i64(t8, t8, sh, len);
> + } else if (me == 63 && rsh + len <= 64) {
> + tcg_gen_extract_i64(t8, t8, rsh, len);
> + } else {
> + tcg_gen_rotli_i64(t8, t8, sh);
> + tcg_gen_andi_i64(t8, t8, mask_u64(mb, me));
> + }
> + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8);
> + if (unlikely(a->rc != 0)) {
> + gen_set_Rc0_i64(ctx, t8);
> + }
> + return true;
> +}
> +#endif
> +
> +static bool trans_RLDICL(DisasContext *ctx, arg_RLDICL *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + return gen_rldinm_i64(ctx, a, a->mb, 63, a->sh);
> +#endif
> +}
> +
> +static bool trans_RLDICR(DisasContext *ctx, arg_RLDICR *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + return gen_rldinm_i64(ctx, a, 0, a->mb, a->sh);
> +#endif
> +}
> +
>
> Hey Glenn,
>
> Do you think we can make use of TRANS macros here for insns using the common methods. Something like :
>
> TRANS(RLDICL, gen_rldinm_i64, a->mb, 63, a->sh)
> TRANS(RLDICR, gen_rldinm_i64, 0, a->mb, a->sh)
>
> And then have gen_rldinm_i64 like :
>
> static bool gen_rldinm_i64(...)
> {
>
> #if defined(TARGET_PPC64)
> return false;
> #else
> ...
> ...
> #endif
> }
>
> Similarlly for other insns above where possible ?
> Or is there something that I'm not seeing that prevents this ??
>
> Thanks,
> Chinmay
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 2/4] target/ppc: Add IBM PPE42 special instructions
2025-08-26 20:17 ` [PATCH v2 2/4] target/ppc: Add IBM PPE42 special instructions Glenn Miles
2025-09-04 12:24 ` Chinmay Rath
@ 2025-09-04 12:30 ` Chinmay Rath
2025-09-04 14:56 ` Miles Glenn
1 sibling, 1 reply; 14+ messages in thread
From: Chinmay Rath @ 2025-09-04 12:30 UTC (permalink / raw)
To: Glenn Miles, qemu-devel
Cc: qemu-ppc, clg, npiggin, harshpb, thuth, richard.henderson
On 8/27/25 01:47, Glenn Miles wrote:
> Adds the following instructions exclusively for
> IBM PPE42 processors:
>
> LSKU
> LCXU
> STSKU
> STCXU
> LVD
> LVDU
> LVDX
> STVD
> STVDU
> STVDX
> SLVD
> SRVD
> CMPWBC
> CMPLWBC
> CMPWIBC
> BNBWI
> BNBW
> CLRBWIBC
> CLRWBC
> DCBQ
> RLDICL
> RLDICR
> RLDIMI
>
> A PPE42 GCC compiler is available here:
> https://github.com/open-power/ppe42-gcc
>
> For more information on the PPE42 processors please visit:
> https://wiki.raptorcs.com/w/images/a/a3/PPE_42X_Core_Users_Manual.pdf
>
> Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
> ---
> target/ppc/insn32.decode | 66 ++-
> target/ppc/translate.c | 29 +-
> target/ppc/translate/ppe-impl.c.inc | 805 ++++++++++++++++++++++++++++
> 3 files changed, 890 insertions(+), 10 deletions(-)
> create mode 100644 target/ppc/translate/ppe-impl.c.inc
>
> diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
> index e53fd2840d..8beb588a2a 100644
> --- a/target/ppc/insn32.decode
> +++ b/target/ppc/insn32.decode
> @@ -58,6 +58,10 @@
> %ds_rtp 22:4 !function=times_2
> @DS_rtp ...... ....0 ra:5 .............. .. &D rt=%ds_rtp si=%ds_si
>
> +%dd_si 3:s13
> +&DD rt ra si:int64_t
> +@DD ...... rt:5 ra:5 ............. . .. &DD si=%dd_si
> +
> &DX_b vrt b
> %dx_b 6:10 16:5 0:1
> @DX_b ...... vrt:5 ..... .......... ..... . &DX_b b=%dx_b
> @@ -66,6 +70,11 @@
> %dx_d 6:s10 16:5 0:1
> @DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d
>
> +%md_sh 1:1 11:5
> +%md_mb 5:1 6:5
> +&MD rs ra sh mb rc
> +@MD ...... rs:5 ra:5 ..... ...... ... . rc:1 &MD sh=%md_sh mb=%md_mb
> +
> &VA vrt vra vrb rc
> @VA ...... vrt:5 vra:5 vrb:5 rc:5 ...... &VA
>
> @@ -322,6 +331,13 @@ LDUX 011111 ..... ..... ..... 0000110101 - @X
>
> LQ 111000 ..... ..... ............ ---- @DQ_rtp
>
> +LVD 000101 ..... ..... ................ @D
> +LVDU 001001 ..... ..... ................ @D
> +LVDX 011111 ..... ..... ..... 0000010001 - @X
> +LSKU 111010 ..... ..... ............. 0 11 @DD
> +LCXU 111010 ..... ..... ............. 1 11 @DD
> +
> +
> ### Fixed-Point Store Instructions
>
> STB 100110 ..... ..... ................ @D
> @@ -346,6 +362,11 @@ STDUX 011111 ..... ..... ..... 0010110101 - @X
>
> STQ 111110 ..... ..... ..............10 @DS_rtp
>
> +STVDU 010110 ..... ..... ................ @D
> +STVDX 011111 ..... ..... ..... 0010010001 - @X
> +STSKU 111110 ..... ..... ............. 0 11 @DD
> +STCXU 111110 ..... ..... ............. 1 11 @DD
> +
> ### Fixed-Point Compare Instructions
>
> CMP 011111 ... - . ..... ..... 0000000000 - @X_bfl
> @@ -461,8 +482,14 @@ PRTYD 011111 ..... ..... ----- 0010111010 - @X_sa
>
> BPERMD 011111 ..... ..... ..... 0011111100 - @X
> CFUGED 011111 ..... ..... ..... 0011011100 - @X
> -CNTLZDM 011111 ..... ..... ..... 0000111011 - @X
> -CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
> +{
> + SLVD 011111 ..... ..... ..... 0000111011 . @X_rc
> + CNTLZDM 011111 ..... ..... ..... 0000111011 - @X
> +}
> +{
> + SRVD 011111 ..... ..... ..... 1000111011 . @X_rc
> + CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
> +}
> PDEPD 011111 ..... ..... ..... 0010011100 - @X
> PEXTD 011111 ..... ..... ..... 0010111100 - @X
>
> @@ -981,8 +1008,16 @@ LXSSP 111001 ..... ..... .............. 11 @DS
> STXSSP 111101 ..... ..... .............. 11 @DS
> LXV 111101 ..... ..... ............ . 001 @DQ_TSX
> STXV 111101 ..... ..... ............ . 101 @DQ_TSX
> -LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP
> -STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP
> +
> +# STVD PPE instruction overlaps with the LXVP and STXVP instructions
> +{
> + STVD 000110 ..... ..... ................ @D
> + [
> + LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP
> + STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP
> + ]
> +}
> +
> LXVX 011111 ..... ..... ..... 0100 - 01100 . @X_TSX
> STXVX 011111 ..... ..... ..... 0110001100 . @X_TSX
> LXVPX 011111 ..... ..... ..... 0101001101 - @X_TSXP
> @@ -1300,3 +1335,26 @@ CLRBHRB 011111 ----- ----- ----- 0110101110 -
> ## Misc POWER instructions
>
> ATTN 000000 00000 00000 00000 0100000000 0
> +
> +# Fused compare-branch instructions for PPE only
> +%fcb_bdx 1:s10 !function=times_4
> +&FCB px:bool ra rb:uint64_t bdx lk:bool
> +@FCB ...... .. px:1 .. ra:5 rb:5 .......... lk:1 &FCB bdx=%fcb_bdx
> +&FCB_bix px:bool bix ra rb:uint64_t bdx lk:bool
> +@FCB_bix ...... .. px:1 bix:2 ra:5 rb:5 .......... lk:1 &FCB_bix bdx=%fcb_bdx
> +
> +CMPWBC 000001 00 . .. ..... ..... .......... . @FCB_bix
> +CMPLWBC 000001 01 . .. ..... ..... .......... . @FCB_bix
> +CMPWIBC 000001 10 . .. ..... ..... .......... . @FCB_bix
> +BNBWI 000001 11 . 00 ..... ..... .......... . @FCB
> +BNBW 000001 11 . 01 ..... ..... .......... . @FCB
> +CLRBWIBC 000001 11 . 10 ..... ..... .......... . @FCB
> +CLRBWBC 000001 11 . 11 ..... ..... .......... . @FCB
> +
> +# Data Cache Block Query for PPE only
> +DCBQ 011111 ..... ..... ..... 0110010110 - @X
> +
> +# Rotate Doubleword Instructions for PPE only (if TARGET_PPC64 not defined)
> +RLDICL 011110 ..... ..... ..... ...... 000 . . @MD
> +RLDICR 011110 ..... ..... ..... ...... 001 . . @MD
> +RLDIMI 011110 ..... ..... ..... ...... 011 . . @MD
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index fc817dab54..d422789a1d 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -209,6 +209,11 @@ struct DisasContext {
> #define DISAS_CHAIN DISAS_TARGET_2 /* lookup next tb, pc updated */
> #define DISAS_CHAIN_UPDATE DISAS_TARGET_3 /* lookup next tb, pc stale */
>
> +static inline bool is_ppe(const DisasContext *ctx)
> +{
> + return !!(ctx->flags & POWERPC_FLAG_PPE42);
> +}
> +
> /* Return true iff byteswap is needed in a scalar memop */
> static inline bool need_byteswap(const DisasContext *ctx)
> {
> @@ -556,11 +561,8 @@ void spr_access_nop(DisasContext *ctx, int sprn, int gprn)
>
> #endif
>
> -/* SPR common to all PowerPC */
> -/* XER */
> -void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
> +static void gen_get_xer(DisasContext *ctx, TCGv dst)
> {
> - TCGv dst = cpu_gpr[gprn];
> TCGv t0 = tcg_temp_new();
> TCGv t1 = tcg_temp_new();
> TCGv t2 = tcg_temp_new();
> @@ -579,9 +581,16 @@ void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
> }
> }
>
> -void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
> +/* SPR common to all PowerPC */
> +/* XER */
> +void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
> +{
> + TCGv dst = cpu_gpr[gprn];
> + gen_get_xer(ctx, dst);
> +}
> +
> +static void gen_set_xer(DisasContext *ctx, TCGv src)
> {
> - TCGv src = cpu_gpr[gprn];
> /* Write all flags, while reading back check for isa300 */
> tcg_gen_andi_tl(cpu_xer, src,
> ~((1u << XER_SO) |
> @@ -594,6 +603,12 @@ void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
> tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1);
> }
>
> +void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
> +{
> + TCGv src = cpu_gpr[gprn];
> + gen_set_xer(ctx, src);
> +}
> +
> /* LR */
> void spr_read_lr(DisasContext *ctx, int gprn, int sprn)
> {
> @@ -5755,6 +5770,8 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a)
>
> #include "translate/bhrb-impl.c.inc"
>
> +#include "translate/ppe-impl.c.inc"
> +
> /* Handles lfdp */
> static void gen_dform39(DisasContext *ctx)
> {
> diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ppe-impl.c.inc
> new file mode 100644
> index 0000000000..98fd794aa4
> --- /dev/null
> +++ b/target/ppc/translate/ppe-impl.c.inc
> @@ -0,0 +1,805 @@
> +/*
> + * IBM PPE Instructions
> + *
> + * Copyright (c) 2024, IBM Corporation.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +
> +#if !defined(TARGET_PPC64)
> +static bool vdr_is_valid(uint32_t vdr)
> +{
> + const uint32_t valid_bitmap = 0xf00003ff;
> + return !!((1ul << (vdr & 0x1f)) & valid_bitmap);
> +}
> +
> +static bool ppe_gpr_is_valid(uint32_t reg)
> +{
> + const uint32_t valid_bitmap = 0xf00027ff;
> + return !!((1ul << (reg & 0x1f)) & valid_bitmap);
> +}
> +#endif
> +
> +#define CHECK_VDR(CTX, VDR) \
> + do { \
> + if (unlikely(!vdr_is_valid(VDR))) { \
> + gen_invalid(CTX); \
> + return true; \
> + } \
> + } while (0)
> +
> +#define CHECK_PPE_GPR(CTX, REG) \
> + do { \
> + if (unlikely(!ppe_gpr_is_valid(REG))) { \
> + gen_invalid(CTX); \
> + return true; \
> + } \
> + } while (0)
> +
> +#define CHECK_VDR(CTX, VDR) \
> + do { \
> + if (unlikely(!vdr_is_valid(VDR))) { \
> + gen_invalid(CTX); \
> + return true; \
> + } \
> + } while (0)
> +
> +#define VDR_PAIR_REG(VDR) (((VDR) + 1) & 0x1f)
> +
> +#define CHECK_PPE_LEVEL(CTX, LVL) \
> + do { \
> + if (unlikely(!((CTX)->insns_flags2 & (LVL)))) { \
> + gen_invalid(CTX); \
> + return true; \
> + } \
> + } while (0)
> +
> +static bool trans_LCXU(DisasContext *ctx, arg_LCXU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + int i;
> + TCGv base, EA;
> + TCGv lo, hi;
> + TCGv_i64 t8;
> + const uint8_t vd_list[] = {9, 7, 5, 3, 0};
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_PPE_GPR(ctx, a->rt);
> +
> + if (unlikely((a->rt != a->ra) || (a->ra == 0) || (a->si < 0xB))) {
> + gen_invalid(ctx);
> + return true;
> + }
> +
> + EA = tcg_temp_new();
> + base = tcg_temp_new();
> +
> + tcg_gen_addi_tl(base, cpu_gpr[a->ra], a->si * 8);
> + gen_store_spr(SPR_PPE42_EDR, base);
> +
> + t8 = tcg_temp_new_i64();
> +
> + tcg_gen_addi_tl(EA, base, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(cpu_gpr[31], cpu_gpr[30], t8);
> +
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(cpu_gpr[29], cpu_gpr[28], t8);
> +
> + lo = tcg_temp_new();
> + hi = tcg_temp_new();
> +
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(lo, hi, t8);
> + gen_store_spr(SPR_SRR0, hi);
> + gen_store_spr(SPR_SRR1, lo);
> +
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(lo, hi, t8);
> + gen_set_xer(ctx, hi);
> + tcg_gen_mov_tl(cpu_ctr, lo);
> +
> + for (i = 0; i < sizeof(vd_list); i++) {
> + int vd = vd_list[i];
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd], t8);
> + }
> +
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + tcg_gen_extr_i64_tl(lo, hi, t8);
> + tcg_gen_shri_tl(hi, hi, 28);
> + tcg_gen_trunc_tl_i32(cpu_crf[0], hi);
> + gen_store_spr(SPR_SPRG0, lo);
> +
> + tcg_gen_addi_tl(EA, base, 4);
> + tcg_gen_qemu_ld_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> + tcg_gen_mov_tl(cpu_gpr[a->ra], base);
> + return true;
> +#endif
> +}
> +
> +static bool trans_LSKU(DisasContext *ctx, arg_LSKU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + int64_t n;
> + TCGv base, EA;
> + TCGv_i32 lo, hi;
> + TCGv_i64 t8;
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> +
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_PPE_GPR(ctx, a->rt);
> +
> + if (unlikely((a->rt != a->ra) || (a->ra == 0) ||
> + (a->si & PPC_BIT(0)) || (a->si == 0))) {
> + gen_invalid(ctx);
> + return true;
> + }
> +
> + EA = tcg_temp_new();
> + base = tcg_temp_new();
> + gen_addr_register(ctx, base);
> +
> +
> + tcg_gen_addi_tl(base, base, a->si * 8);
> + gen_store_spr(SPR_PPE42_EDR, base);
> +
> + n = a->si - 1;
> + t8 = tcg_temp_new_i64();
> + if (n > 0) {
> + tcg_gen_addi_tl(EA, base, -8);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + hi = cpu_gpr[30];
> + lo = cpu_gpr[31];
> + tcg_gen_extr_i64_i32(lo, hi, t8);
> + }
> + if (n > 1) {
> + tcg_gen_addi_tl(EA, base, -16);
> + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + hi = cpu_gpr[28];
> + lo = cpu_gpr[29];
> + tcg_gen_extr_i64_i32(lo, hi, t8);
> + }
> + tcg_gen_addi_tl(EA, base, 4);
> + tcg_gen_qemu_ld_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> + tcg_gen_mov_tl(cpu_gpr[a->ra], base);
> + return true;
> +#endif
> +}
> +
> +static bool trans_STCXU(DisasContext *ctx, arg_STCXU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + TCGv EA;
> + TCGv lo, hi;
> + TCGv_i64 t8;
> + int i;
> + const uint8_t vd_list[] = {9, 7, 5, 3, 0};
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> +
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_PPE_GPR(ctx, a->rt);
> +
> + if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) {
> + gen_invalid(ctx);
> + return true;
> + }
> +
> + EA = tcg_temp_new();
> + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], 4);
> + tcg_gen_qemu_st_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> +
> + gen_store_spr(SPR_PPE42_EDR, cpu_gpr[a->ra]);
> +
> + t8 = tcg_temp_new_i64();
> +
> + tcg_gen_concat_tl_i64(t8, cpu_gpr[31], cpu_gpr[30]);
> + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> +
> + tcg_gen_concat_tl_i64(t8, cpu_gpr[29], cpu_gpr[28]);
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> +
> + lo = tcg_temp_new();
> + hi = tcg_temp_new();
> +
> + gen_load_spr(hi, SPR_SRR0);
> + gen_load_spr(lo, SPR_SRR1);
> + tcg_gen_concat_tl_i64(t8, lo, hi);
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> +
> + gen_get_xer(ctx, hi);
> + tcg_gen_mov_tl(lo, cpu_ctr);
> + tcg_gen_concat_tl_i64(t8, lo, hi);
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> +
> + for (i = 0; i < sizeof(vd_list); i++) {
> + int vd = vd_list[i];
> + tcg_gen_concat_tl_i64(t8, cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd]);
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + }
> +
> + gen_load_spr(lo, SPR_SPRG0);
> + tcg_gen_extu_i32_tl(hi, cpu_crf[0]);
> + tcg_gen_shli_tl(hi, hi, 28);
> + tcg_gen_concat_tl_i64(t8, lo, hi);
> + tcg_gen_addi_tl(EA, EA, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> +
> + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], a->si * 8);
> + tcg_gen_qemu_st_i32(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) |
> + MO_ALIGN);
> + tcg_gen_mov_tl(cpu_gpr[a->ra], EA);
> + return true;
> +#endif
> +}
> +
> +static bool trans_STSKU(DisasContext *ctx, arg_STSKU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + int64_t n;
> + TCGv base, EA;
> + TCGv_i32 lo, hi;
> + TCGv_i64 t8;
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> +
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_PPE_GPR(ctx, a->rt);
> +
> + if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) {
> + gen_invalid(ctx);
> + return true;
> + }
> +
> + EA = tcg_temp_new();
> + base = tcg_temp_new();
> + gen_addr_register(ctx, base);
> + tcg_gen_addi_tl(EA, base, 4);
> + tcg_gen_qemu_st_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> +
> + gen_store_spr(SPR_PPE42_EDR, base);
> +
> + n = ~(a->si);
> +
> + t8 = tcg_temp_new_i64();
> + if (n > 0) {
> + hi = cpu_gpr[30];
> + lo = cpu_gpr[31];
> + tcg_gen_concat_i32_i64(t8, lo, hi);
> + tcg_gen_addi_tl(EA, base, -8);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + }
> + if (n > 1) {
> + hi = cpu_gpr[28];
> + lo = cpu_gpr[29];
> + tcg_gen_concat_i32_i64(t8, lo, hi);
> + tcg_gen_addi_tl(EA, base, -16);
> + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> + }
> +
> + tcg_gen_addi_tl(EA, base, a->si * 8);
> + tcg_gen_qemu_st_i32(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) |
> + MO_ALIGN);
> + tcg_gen_mov_tl(cpu_gpr[a->ra], EA);
> + return true;
> +#endif
> +}
> +
> +#if !defined(TARGET_PPC64)
> +static bool do_ppe_ldst(DisasContext *ctx, int rt, int ra, TCGv displ,
> + bool update, bool store)
> +{
> + TCGv ea;
> + int rt_lo;
> + TCGv_i64 t8;
> +
> + CHECK_VDR(ctx, rt);
> + CHECK_PPE_GPR(ctx, ra);
> + rt_lo = VDR_PAIR_REG(rt);
> + if (update && (ra == 0 || (!store && ((ra == rt) || (ra == rt_lo))))) {
> + gen_invalid(ctx);
> + return true;
> + }
> + gen_set_access_type(ctx, ACCESS_INT);
> +
> + ea = do_ea_calc(ctx, ra, displ);
> + t8 = tcg_temp_new_i64();
> + if (store) {
> + tcg_gen_concat_i32_i64(t8, cpu_gpr[rt_lo], cpu_gpr[rt]);
> + tcg_gen_qemu_st_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64));
> + } else {
> + tcg_gen_qemu_ld_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64));
> + tcg_gen_extr_i64_i32(cpu_gpr[rt_lo], cpu_gpr[rt], t8);
> + }
> + if (update) {
> + tcg_gen_mov_tl(cpu_gpr[ra], ea);
> + }
> + return true;
> +}
> +#endif
> +
> +static bool trans_LVD(DisasContext *ctx, arg_LVD *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), false, false);
> +#endif
> +}
> +
> +static bool trans_LVDU(DisasContext *ctx, arg_LVDU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), true, false);
> +#endif
> +}
> +
> +static bool trans_LVDX(DisasContext *ctx, arg_LVDX *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, false);
> +#endif
> +}
> +
> +static bool trans_STVD(DisasContext *ctx, arg_STVD *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), false, true);
> +#endif
> +}
> +
> +static bool trans_STVDU(DisasContext *ctx, arg_STVDU *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), true, true);
> +#endif
> +}
> +
> +static bool trans_STVDX(DisasContext *ctx, arg_STVDX *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, true);
> +#endif
> +}
> +
> +#if !defined(TARGET_PPC64)
> +static bool do_fcb(DisasContext *ctx, TCGv ra_val, TCGv rb_val, int bix,
> + int32_t bdx, bool s, bool px, bool lk)
> +{
> + TCGCond cond;
> + uint32_t mask;
> + TCGLabel *no_branch;
> + target_ulong dest;
> +
> + /* Update CR0 */
> + gen_op_cmp32(ra_val, rb_val, s, 0);
> +
> + if (lk) {
> + gen_setlr(ctx, ctx->base.pc_next);
> + }
> +
> +
> + mask = PPC_BIT32(28 + bix);
> + cond = (px) ? TCG_COND_TSTEQ : TCG_COND_TSTNE;
> + no_branch = gen_new_label();
> + dest = ctx->cia + bdx;
> +
> + /* Do the branch if CR0[bix] == PX */
> + tcg_gen_brcondi_i32(cond, cpu_crf[0], mask, no_branch);
> + gen_goto_tb(ctx, 0, dest);
> + gen_set_label(no_branch);
> + gen_goto_tb(ctx, 1, ctx->base.pc_next);
> + ctx->base.is_jmp = DISAS_NORETURN;
> + return true;
> +}
> +#endif
> +
> +#if !defined(TARGET_PPC64)
> +static bool do_cmp_branch(DisasContext *ctx, int ra, TCGv rb_val, int bix,
> + int32_t bdx, bool s, bool px, bool lk)
> +{
> + TCGv old_ra;
> +
> + CHECK_PPE_GPR(ctx, ra);
> + if (bix == 3) {
> + old_ra = tcg_temp_new();
> + tcg_gen_mov_tl(old_ra, cpu_gpr[ra]);
> + tcg_gen_sub_tl(cpu_gpr[ra], cpu_gpr[ra], rb_val);
> + return do_fcb(ctx, old_ra, rb_val, 2,
> + bdx, s, px, lk);
> + } else {
> + return do_fcb(ctx, cpu_gpr[ra], rb_val, bix,
> + bdx, s, px, lk);
> + }
> +}
> +#endif
> +
> +#if !defined(TARGET_PPC64)
> +static bool do_mask_branch(DisasContext *ctx, int ra, TCGv mask,
> + int32_t bdx, bool invert, bool px, bool lk,
> + bool update)
> +{
> + TCGv r;
> + CHECK_PPE_GPR(ctx, ra);
> + if (invert) {
> + tcg_gen_not_tl(mask, mask);
> + }
> +
> + /* apply mask to ra */
> + r = tcg_temp_new();
> + tcg_gen_and_tl(r, cpu_gpr[ra], mask);
> + if (update) {
> + tcg_gen_mov_tl(cpu_gpr[ra], r);
> + }
> + return do_fcb(ctx, r, tcg_constant_tl(0), 2,
> + bdx, false, px, lk);
> +}
> +#endif
> +
> +static bool trans_CMPWBC(DisasContext *ctx, arg_CMPWBC *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + return do_cmp_branch(ctx, a->ra, cpu_gpr[a->rb], a->bix, a->bdx,
> + true, a->px, a->lk);
> +#endif
> +}
> +
> +static bool trans_CMPLWBC(DisasContext *ctx, arg_CMPLWBC *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + return do_cmp_branch(ctx, a->ra, cpu_gpr[a->rb], a->bix, a->bdx,
> + false, a->px, a->lk);
> +#endif
> +}
> +
> +static bool trans_CMPWIBC(DisasContext *ctx, arg_CMPWIBC *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_cmp_branch(ctx, a->ra, tcg_constant_tl(a->rb), a->bix, a->bdx,
> + true, a->px, a->lk);
> +#endif
> +}
> +
> +static bool trans_BNBWI(DisasContext *ctx, arg_BNBWI *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_mask_branch(ctx, a->ra, tcg_constant_tl(PPC_BIT32(a->rb)),
> + a->bdx, false, a->px, a->lk, false);
> +#endif
> +}
> +
> +static bool trans_BNBW(DisasContext *ctx, arg_BNBW *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + TCGv mask, shift;
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + mask = tcg_temp_new();
> + shift = tcg_temp_new();
> + tcg_gen_andi_tl(shift, cpu_gpr[a->rb], 0x1f);
> + tcg_gen_shr_tl(mask, tcg_constant_tl(0x80000000), shift);
> + return do_mask_branch(ctx, a->ra, mask, a->bdx, false, a->px, a->lk, false);
> +#endif
> +}
> +
> +static bool trans_CLRBWIBC(DisasContext *ctx, arg_CLRBWIBC *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + return do_mask_branch(ctx, a->ra, tcg_constant_tl(PPC_BIT32(a->rb)),
> + a->bdx, true, a->px, a->lk, true);
> +#endif
> +}
> +
> +static bool trans_CLRBWBC(DisasContext *ctx, arg_CLRBWBC *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + TCGv mask, shift;
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_GPR(ctx, a->rb);
> + mask = tcg_temp_new();
> + shift = tcg_temp_new();
> + tcg_gen_andi_tl(shift, cpu_gpr[a->rb], 0x1f);
> + tcg_gen_shr_tl(mask, tcg_constant_tl(0x80000000), shift);
> + return do_mask_branch(ctx, a->ra, mask, a->bdx, true, a->px, a->lk, true);
> +#endif
> +}
> +
> +#if !defined(TARGET_PPC64)
> +static void gen_set_Rc0_i64(DisasContext *ctx, TCGv_i64 reg)
> +{
> + TCGv_i64 t0 = tcg_temp_new_i64();
> + TCGv_i64 t1 = tcg_temp_new_i64();
> + TCGv_i32 t = tcg_temp_new_i32();
> +
> + tcg_gen_movi_i64(t0, CRF_EQ);
> + tcg_gen_movi_i64(t1, CRF_LT);
> + tcg_gen_movcond_i64(TCG_COND_LT, t0, reg, tcg_constant_i64(0), t1, t0);
> + tcg_gen_movi_i64(t1, CRF_GT);
> + tcg_gen_movcond_i64(TCG_COND_GT, t0, reg, tcg_constant_i64(0), t1, t0);
> + tcg_gen_extrl_i64_i32(t, t0);
> + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
> + tcg_gen_or_i32(cpu_crf[0], cpu_crf[0], t);
> +}
> +#endif
> +
> +#if !defined(TARGET_PPC64)
> +static bool do_shift64(DisasContext *ctx, arg_X_rc *a, bool left)
> +{
> + int rt_lo, ra_lo;
> + TCGv_i64 t0, t8;
> +
> + /* Check for PPE since opcode overlaps with CNTTZDM instruction */
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_VDR(ctx, a->rt);
> + CHECK_VDR(ctx, a->ra);
> + CHECK_PPE_GPR(ctx, a->rb);
> + rt_lo = VDR_PAIR_REG(a->rt);
> + ra_lo = VDR_PAIR_REG(a->ra);
> + t8 = tcg_temp_new_i64();
> +
> + /* AND rt with a mask that is 0 when rb >= 0x40 */
> + t0 = tcg_temp_new_i64();
> + tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]);
> + tcg_gen_shli_i64(t0, t0, 0x39);
> + tcg_gen_sari_i64(t0, t0, 0x3f);
> +
> + /* form 64bit value from two 32bit regs */
> + tcg_gen_concat_tl_i64(t8, cpu_gpr[rt_lo], cpu_gpr[a->rt]);
> +
> + /* apply mask */
> + tcg_gen_andc_i64(t8, t8, t0);
> +
> + /* do the shift */
> + tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]);
> + tcg_gen_andi_i64(t0, t0, 0x3f);
> + if (left) {
> + tcg_gen_shl_i64(t8, t8, t0);
> + } else {
> + tcg_gen_shr_i64(t8, t8, t0);
> + }
> +
> + /* split the 64bit word back into two 32bit regs */
> + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8);
> +
> + /* update CR0 if requested */
> + if (unlikely(a->rc != 0)) {
> + gen_set_Rc0_i64(ctx, t8);
> + }
> + return true;
> +}
> +#endif
> +
> +static bool trans_SRVD(DisasContext *ctx, arg_SRVD *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + return do_shift64(ctx, a, false);
> +#endif
> +}
> +
> +static bool trans_SLVD(DisasContext *ctx, arg_SLVD *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + return do_shift64(ctx, a, true);
> +#endif
> +}
> +
> +static bool trans_DCBQ(DisasContext *ctx, arg_DCBQ *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> +
> + CHECK_PPE_GPR(ctx, a->rt);
> + CHECK_PPE_GPR(ctx, a->ra);
> + CHECK_PPE_GPR(ctx, a->rb);
> +
> + /* No cache exists, so just set RT to 0 */
> + tcg_gen_movi_tl(cpu_gpr[a->rt], 0);
> + return true;
> +#endif
> +}
> +
> +static bool trans_RLDIMI(DisasContext *ctx, arg_RLDIMI *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + TCGv_i64 t_rs, t_ra;
> + int ra_lo, rs_lo;
> + uint32_t sh = a->sh;
> + uint32_t mb = a->mb;
> + uint32_t me = 63 - sh;
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_VDR(ctx, a->rs);
> + CHECK_VDR(ctx, a->ra);
> +
> + rs_lo = VDR_PAIR_REG(a->rs);
> + ra_lo = VDR_PAIR_REG(a->ra);
> +
> + t_rs = tcg_temp_new_i64();
> + t_ra = tcg_temp_new_i64();
> +
> + tcg_gen_concat_tl_i64(t_rs, cpu_gpr[rs_lo], cpu_gpr[a->rs]);
> + tcg_gen_concat_tl_i64(t_ra, cpu_gpr[ra_lo], cpu_gpr[a->ra]);
> +
> + if (mb <= me) {
> + tcg_gen_deposit_i64(t_ra, t_ra, t_rs, sh, me - mb + 1);
> + } else {
> + uint64_t mask = mask_u64(mb, me);
> + TCGv_i64 t1 = tcg_temp_new_i64();
> +
> + tcg_gen_rotli_i64(t1, t_rs, sh);
> + tcg_gen_andi_i64(t1, t1, mask);
> + tcg_gen_andi_i64(t_ra, t_ra, ~mask);
> + tcg_gen_or_i64(t_ra, t_ra, t1);
> + }
> +
> + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t_ra);
> +
> + if (unlikely(a->rc != 0)) {
> + gen_set_Rc0_i64(ctx, t_ra);
> + }
> + return true;
> +#endif
> +}
> +
> +
> +#if !defined(TARGET_PPC64)
> +static bool gen_rldinm_i64(DisasContext *ctx, arg_MD *a, int mb, int me, int sh)
> +{
> + int len = me - mb + 1;
> + int rsh = (64 - sh) & 63;
> + int ra_lo, rs_lo;
> + TCGv_i64 t8;
> +
> + if (unlikely(!is_ppe(ctx))) {
> + return false;
> + }
> + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> + CHECK_VDR(ctx, a->rs);
> + CHECK_VDR(ctx, a->ra);
> +
> + rs_lo = VDR_PAIR_REG(a->rs);
> + ra_lo = VDR_PAIR_REG(a->ra);
> + t8 = tcg_temp_new_i64();
> + tcg_gen_concat_tl_i64(t8, cpu_gpr[rs_lo], cpu_gpr[a->rs]);
> + if (sh != 0 && len > 0 && me == (63 - sh)) {
> + tcg_gen_deposit_z_i64(t8, t8, sh, len);
> + } else if (me == 63 && rsh + len <= 64) {
> + tcg_gen_extract_i64(t8, t8, rsh, len);
> + } else {
> + tcg_gen_rotli_i64(t8, t8, sh);
> + tcg_gen_andi_i64(t8, t8, mask_u64(mb, me));
> + }
> + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8);
> + if (unlikely(a->rc != 0)) {
> + gen_set_Rc0_i64(ctx, t8);
> + }
> + return true;
> +}
> +#endif
> +
> +static bool trans_RLDICL(DisasContext *ctx, arg_RLDICL *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + return gen_rldinm_i64(ctx, a, a->mb, 63, a->sh);
> +#endif
> +}
> +
> +static bool trans_RLDICR(DisasContext *ctx, arg_RLDICR *a)
> +{
> +#if defined(TARGET_PPC64)
> + return false;
> +#else
> + return gen_rldinm_i64(ctx, a, 0, a->mb, a->sh);
> +#endif
> +}
> +
Sorry about the formatting error in the last mail, please ignore.
Hey Glenn,
Do you think we can make use of TRANS macros here for insns using the
common methods. Something like :
TRANS(RLDICL, gen_rldinm_i64, a->mb, 63, a->sh)
TRANS(RLDICR, gen_rldinm_i64, 0, a->mb, a->sh)
And then have gen_rldinm_i64 like :
static bool gen_rldinm_i64(...)
{
#if defined(TARGET_PPC64)
return false;
#else
...
...
#endif
}
Similarlly for other insns above where possible ?
Or is there something that I'm not seeing that prevents this ??
Thanks,
Chinmay
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 2/4] target/ppc: Add IBM PPE42 special instructions
2025-09-04 12:30 ` Chinmay Rath
@ 2025-09-04 14:56 ` Miles Glenn
0 siblings, 0 replies; 14+ messages in thread
From: Miles Glenn @ 2025-09-04 14:56 UTC (permalink / raw)
To: Chinmay Rath, qemu-devel
Cc: qemu-ppc, clg, npiggin, harshpb, thuth, richard.henderson
On Thu, 2025-09-04 at 18:00 +0530, Chinmay Rath wrote:
> On 8/27/25 01:47, Glenn Miles wrote:
> > Adds the following instructions exclusively for
> > IBM PPE42 processors:
> >
> > LSKU
> > LCXU
> > STSKU
> > STCXU
> > LVD
> > LVDU
> > LVDX
> > STVD
> > STVDU
> > STVDX
> > SLVD
> > SRVD
> > CMPWBC
> > CMPLWBC
> > CMPWIBC
> > BNBWI
> > BNBW
> > CLRBWIBC
> > CLRWBC
> > DCBQ
> > RLDICL
> > RLDICR
> > RLDIMI
> >
> > A PPE42 GCC compiler is available here:
> > https://github.com/open-power/ppe42-gcc
> >
> > For more information on the PPE42 processors please visit:
> > https://wiki.raptorcs.com/w/images/a/a3/PPE_42X_Core_Users_Manual.pdf
> >
> > Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
> > ---
> > target/ppc/insn32.decode | 66 ++-
> > target/ppc/translate.c | 29 +-
> > target/ppc/translate/ppe-impl.c.inc | 805 ++++++++++++++++++++++++++++
> > 3 files changed, 890 insertions(+), 10 deletions(-)
> > create mode 100644 target/ppc/translate/ppe-impl.c.inc
> >
> > diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
> > index e53fd2840d..8beb588a2a 100644
> > --- a/target/ppc/insn32.decode
> > +++ b/target/ppc/insn32.decode
> > @@ -58,6 +58,10 @@
> > %ds_rtp 22:4 !function=times_2
> > @DS_rtp ...... ....0 ra:5 .............. .. &D rt=%ds_rtp si=%ds_si
> >
> > +%dd_si 3:s13
> > +&DD rt ra si:int64_t
> > +@DD ...... rt:5 ra:5 ............. . .. &DD si=%dd_si
> > +
> > &DX_b vrt b
> > %dx_b 6:10 16:5 0:1
> > @DX_b ...... vrt:5 ..... .......... ..... . &DX_b b=%dx_b
> > @@ -66,6 +70,11 @@
> > %dx_d 6:s10 16:5 0:1
> > @DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d
> >
> > +%md_sh 1:1 11:5
> > +%md_mb 5:1 6:5
> > +&MD rs ra sh mb rc
> > +@MD ...... rs:5 ra:5 ..... ...... ... . rc:1 &MD sh=%md_sh mb=%md_mb
> > +
> > &VA vrt vra vrb rc
> > @VA ...... vrt:5 vra:5 vrb:5 rc:5 ...... &VA
> >
> > @@ -322,6 +331,13 @@ LDUX 011111 ..... ..... ..... 0000110101 - @X
> >
> > LQ 111000 ..... ..... ............ ---- @DQ_rtp
> >
> > +LVD 000101 ..... ..... ................ @D
> > +LVDU 001001 ..... ..... ................ @D
> > +LVDX 011111 ..... ..... ..... 0000010001 - @X
> > +LSKU 111010 ..... ..... ............. 0 11 @DD
> > +LCXU 111010 ..... ..... ............. 1 11 @DD
> > +
> > +
> > ### Fixed-Point Store Instructions
> >
> > STB 100110 ..... ..... ................ @D
> > @@ -346,6 +362,11 @@ STDUX 011111 ..... ..... ..... 0010110101 - @X
> >
> > STQ 111110 ..... ..... ..............10 @DS_rtp
> >
> > +STVDU 010110 ..... ..... ................ @D
> > +STVDX 011111 ..... ..... ..... 0010010001 - @X
> > +STSKU 111110 ..... ..... ............. 0 11 @DD
> > +STCXU 111110 ..... ..... ............. 1 11 @DD
> > +
> > ### Fixed-Point Compare Instructions
> >
> > CMP 011111 ... - . ..... ..... 0000000000 - @X_bfl
> > @@ -461,8 +482,14 @@ PRTYD 011111 ..... ..... ----- 0010111010 - @X_sa
> >
> > BPERMD 011111 ..... ..... ..... 0011111100 - @X
> > CFUGED 011111 ..... ..... ..... 0011011100 - @X
> > -CNTLZDM 011111 ..... ..... ..... 0000111011 - @X
> > -CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
> > +{
> > + SLVD 011111 ..... ..... ..... 0000111011 . @X_rc
> > + CNTLZDM 011111 ..... ..... ..... 0000111011 - @X
> > +}
> > +{
> > + SRVD 011111 ..... ..... ..... 1000111011 . @X_rc
> > + CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
> > +}
> > PDEPD 011111 ..... ..... ..... 0010011100 - @X
> > PEXTD 011111 ..... ..... ..... 0010111100 - @X
> >
> > @@ -981,8 +1008,16 @@ LXSSP 111001 ..... ..... .............. 11 @DS
> > STXSSP 111101 ..... ..... .............. 11 @DS
> > LXV 111101 ..... ..... ............ . 001 @DQ_TSX
> > STXV 111101 ..... ..... ............ . 101 @DQ_TSX
> > -LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP
> > -STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP
> > +
> > +# STVD PPE instruction overlaps with the LXVP and STXVP instructions
> > +{
> > + STVD 000110 ..... ..... ................ @D
> > + [
> > + LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP
> > + STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP
> > + ]
> > +}
> > +
> > LXVX 011111 ..... ..... ..... 0100 - 01100 . @X_TSX
> > STXVX 011111 ..... ..... ..... 0110001100 . @X_TSX
> > LXVPX 011111 ..... ..... ..... 0101001101 - @X_TSXP
> > @@ -1300,3 +1335,26 @@ CLRBHRB 011111 ----- ----- ----- 0110101110 -
> > ## Misc POWER instructions
> >
> > ATTN 000000 00000 00000 00000 0100000000 0
> > +
> > +# Fused compare-branch instructions for PPE only
> > +%fcb_bdx 1:s10 !function=times_4
> > +&FCB px:bool ra rb:uint64_t bdx lk:bool
> > +@FCB ...... .. px:1 .. ra:5 rb:5 .......... lk:1 &FCB bdx=%fcb_bdx
> > +&FCB_bix px:bool bix ra rb:uint64_t bdx lk:bool
> > +@FCB_bix ...... .. px:1 bix:2 ra:5 rb:5 .......... lk:1 &FCB_bix bdx=%fcb_bdx
> > +
> > +CMPWBC 000001 00 . .. ..... ..... .......... . @FCB_bix
> > +CMPLWBC 000001 01 . .. ..... ..... .......... . @FCB_bix
> > +CMPWIBC 000001 10 . .. ..... ..... .......... . @FCB_bix
> > +BNBWI 000001 11 . 00 ..... ..... .......... . @FCB
> > +BNBW 000001 11 . 01 ..... ..... .......... . @FCB
> > +CLRBWIBC 000001 11 . 10 ..... ..... .......... . @FCB
> > +CLRBWBC 000001 11 . 11 ..... ..... .......... . @FCB
> > +
> > +# Data Cache Block Query for PPE only
> > +DCBQ 011111 ..... ..... ..... 0110010110 - @X
> > +
> > +# Rotate Doubleword Instructions for PPE only (if TARGET_PPC64 not defined)
> > +RLDICL 011110 ..... ..... ..... ...... 000 . . @MD
> > +RLDICR 011110 ..... ..... ..... ...... 001 . . @MD
> > +RLDIMI 011110 ..... ..... ..... ...... 011 . . @MD
> > diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> > index fc817dab54..d422789a1d 100644
> > --- a/target/ppc/translate.c
> > +++ b/target/ppc/translate.c
> > @@ -209,6 +209,11 @@ struct DisasContext {
> > #define DISAS_CHAIN DISAS_TARGET_2 /* lookup next tb, pc updated */
> > #define DISAS_CHAIN_UPDATE DISAS_TARGET_3 /* lookup next tb, pc stale */
> >
> > +static inline bool is_ppe(const DisasContext *ctx)
> > +{
> > + return !!(ctx->flags & POWERPC_FLAG_PPE42);
> > +}
> > +
> > /* Return true iff byteswap is needed in a scalar memop */
> > static inline bool need_byteswap(const DisasContext *ctx)
> > {
> > @@ -556,11 +561,8 @@ void spr_access_nop(DisasContext *ctx, int sprn, int gprn)
> >
> > #endif
> >
> > -/* SPR common to all PowerPC */
> > -/* XER */
> > -void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
> > +static void gen_get_xer(DisasContext *ctx, TCGv dst)
> > {
> > - TCGv dst = cpu_gpr[gprn];
> > TCGv t0 = tcg_temp_new();
> > TCGv t1 = tcg_temp_new();
> > TCGv t2 = tcg_temp_new();
> > @@ -579,9 +581,16 @@ void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
> > }
> > }
> >
> > -void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
> > +/* SPR common to all PowerPC */
> > +/* XER */
> > +void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
> > +{
> > + TCGv dst = cpu_gpr[gprn];
> > + gen_get_xer(ctx, dst);
> > +}
> > +
> > +static void gen_set_xer(DisasContext *ctx, TCGv src)
> > {
> > - TCGv src = cpu_gpr[gprn];
> > /* Write all flags, while reading back check for isa300 */
> > tcg_gen_andi_tl(cpu_xer, src,
> > ~((1u << XER_SO) |
> > @@ -594,6 +603,12 @@ void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
> > tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1);
> > }
> >
> > +void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
> > +{
> > + TCGv src = cpu_gpr[gprn];
> > + gen_set_xer(ctx, src);
> > +}
> > +
> > /* LR */
> > void spr_read_lr(DisasContext *ctx, int gprn, int sprn)
> > {
> > @@ -5755,6 +5770,8 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a)
> >
> > #include "translate/bhrb-impl.c.inc"
> >
> > +#include "translate/ppe-impl.c.inc"
> > +
> > /* Handles lfdp */
> > static void gen_dform39(DisasContext *ctx)
> > {
> > diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ppe-impl.c.inc
> > new file mode 100644
> > index 0000000000..98fd794aa4
> > --- /dev/null
> > +++ b/target/ppc/translate/ppe-impl.c.inc
> > @@ -0,0 +1,805 @@
> > +/*
> > + * IBM PPE Instructions
> > + *
> > + * Copyright (c) 2024, IBM Corporation.
> > + *
> > + * SPDX-License-Identifier: GPL-2.0-or-later
> > + */
> > +
> > +
> > +#if !defined(TARGET_PPC64)
> > +static bool vdr_is_valid(uint32_t vdr)
> > +{
> > + const uint32_t valid_bitmap = 0xf00003ff;
> > + return !!((1ul << (vdr & 0x1f)) & valid_bitmap);
> > +}
> > +
> > +static bool ppe_gpr_is_valid(uint32_t reg)
> > +{
> > + const uint32_t valid_bitmap = 0xf00027ff;
> > + return !!((1ul << (reg & 0x1f)) & valid_bitmap);
> > +}
> > +#endif
> > +
> > +#define CHECK_VDR(CTX, VDR) \
> > + do { \
> > + if (unlikely(!vdr_is_valid(VDR))) { \
> > + gen_invalid(CTX); \
> > + return true; \
> > + } \
> > + } while (0)
> > +
> > +#define CHECK_PPE_GPR(CTX, REG) \
> > + do { \
> > + if (unlikely(!ppe_gpr_is_valid(REG))) { \
> > + gen_invalid(CTX); \
> > + return true; \
> > + } \
> > + } while (0)
> > +
> > +#define CHECK_VDR(CTX, VDR) \
> > + do { \
> > + if (unlikely(!vdr_is_valid(VDR))) { \
> > + gen_invalid(CTX); \
> > + return true; \
> > + } \
> > + } while (0)
> > +
> > +#define VDR_PAIR_REG(VDR) (((VDR) + 1) & 0x1f)
> > +
> > +#define CHECK_PPE_LEVEL(CTX, LVL) \
> > + do { \
> > + if (unlikely(!((CTX)->insns_flags2 & (LVL)))) { \
> > + gen_invalid(CTX); \
> > + return true; \
> > + } \
> > + } while (0)
> > +
> > +static bool trans_LCXU(DisasContext *ctx, arg_LCXU *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + int i;
> > + TCGv base, EA;
> > + TCGv lo, hi;
> > + TCGv_i64 t8;
> > + const uint8_t vd_list[] = {9, 7, 5, 3, 0};
> > +
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> > + CHECK_PPE_GPR(ctx, a->rt);
> > +
> > + if (unlikely((a->rt != a->ra) || (a->ra == 0) || (a->si < 0xB))) {
> > + gen_invalid(ctx);
> > + return true;
> > + }
> > +
> > + EA = tcg_temp_new();
> > + base = tcg_temp_new();
> > +
> > + tcg_gen_addi_tl(base, cpu_gpr[a->ra], a->si * 8);
> > + gen_store_spr(SPR_PPE42_EDR, base);
> > +
> > + t8 = tcg_temp_new_i64();
> > +
> > + tcg_gen_addi_tl(EA, base, -8);
> > + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > + tcg_gen_extr_i64_tl(cpu_gpr[31], cpu_gpr[30], t8);
> > +
> > + tcg_gen_addi_tl(EA, EA, -8);
> > + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > + tcg_gen_extr_i64_tl(cpu_gpr[29], cpu_gpr[28], t8);
> > +
> > + lo = tcg_temp_new();
> > + hi = tcg_temp_new();
> > +
> > + tcg_gen_addi_tl(EA, EA, -8);
> > + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > + tcg_gen_extr_i64_tl(lo, hi, t8);
> > + gen_store_spr(SPR_SRR0, hi);
> > + gen_store_spr(SPR_SRR1, lo);
> > +
> > + tcg_gen_addi_tl(EA, EA, -8);
> > + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > + tcg_gen_extr_i64_tl(lo, hi, t8);
> > + gen_set_xer(ctx, hi);
> > + tcg_gen_mov_tl(cpu_ctr, lo);
> > +
> > + for (i = 0; i < sizeof(vd_list); i++) {
> > + int vd = vd_list[i];
> > + tcg_gen_addi_tl(EA, EA, -8);
> > + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > + tcg_gen_extr_i64_tl(cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd], t8);
> > + }
> > +
> > + tcg_gen_addi_tl(EA, EA, -8);
> > + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > + tcg_gen_extr_i64_tl(lo, hi, t8);
> > + tcg_gen_shri_tl(hi, hi, 28);
> > + tcg_gen_trunc_tl_i32(cpu_crf[0], hi);
> > + gen_store_spr(SPR_SPRG0, lo);
> > +
> > + tcg_gen_addi_tl(EA, base, 4);
> > + tcg_gen_qemu_ld_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> > + tcg_gen_mov_tl(cpu_gpr[a->ra], base);
> > + return true;
> > +#endif
> > +}
> > +
> > +static bool trans_LSKU(DisasContext *ctx, arg_LSKU *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + int64_t n;
> > + TCGv base, EA;
> > + TCGv_i32 lo, hi;
> > + TCGv_i64 t8;
> > +
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > +
> > + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> > + CHECK_PPE_GPR(ctx, a->rt);
> > +
> > + if (unlikely((a->rt != a->ra) || (a->ra == 0) ||
> > + (a->si & PPC_BIT(0)) || (a->si == 0))) {
> > + gen_invalid(ctx);
> > + return true;
> > + }
> > +
> > + EA = tcg_temp_new();
> > + base = tcg_temp_new();
> > + gen_addr_register(ctx, base);
> > +
> > +
> > + tcg_gen_addi_tl(base, base, a->si * 8);
> > + gen_store_spr(SPR_PPE42_EDR, base);
> > +
> > + n = a->si - 1;
> > + t8 = tcg_temp_new_i64();
> > + if (n > 0) {
> > + tcg_gen_addi_tl(EA, base, -8);
> > + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > + hi = cpu_gpr[30];
> > + lo = cpu_gpr[31];
> > + tcg_gen_extr_i64_i32(lo, hi, t8);
> > + }
> > + if (n > 1) {
> > + tcg_gen_addi_tl(EA, base, -16);
> > + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > + hi = cpu_gpr[28];
> > + lo = cpu_gpr[29];
> > + tcg_gen_extr_i64_i32(lo, hi, t8);
> > + }
> > + tcg_gen_addi_tl(EA, base, 4);
> > + tcg_gen_qemu_ld_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> > + tcg_gen_mov_tl(cpu_gpr[a->ra], base);
> > + return true;
> > +#endif
> > +}
> > +
> > +static bool trans_STCXU(DisasContext *ctx, arg_STCXU *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + TCGv EA;
> > + TCGv lo, hi;
> > + TCGv_i64 t8;
> > + int i;
> > + const uint8_t vd_list[] = {9, 7, 5, 3, 0};
> > +
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > +
> > + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> > + CHECK_PPE_GPR(ctx, a->rt);
> > +
> > + if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) {
> > + gen_invalid(ctx);
> > + return true;
> > + }
> > +
> > + EA = tcg_temp_new();
> > + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], 4);
> > + tcg_gen_qemu_st_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> > +
> > + gen_store_spr(SPR_PPE42_EDR, cpu_gpr[a->ra]);
> > +
> > + t8 = tcg_temp_new_i64();
> > +
> > + tcg_gen_concat_tl_i64(t8, cpu_gpr[31], cpu_gpr[30]);
> > + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], -8);
> > + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > +
> > + tcg_gen_concat_tl_i64(t8, cpu_gpr[29], cpu_gpr[28]);
> > + tcg_gen_addi_tl(EA, EA, -8);
> > + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > +
> > + lo = tcg_temp_new();
> > + hi = tcg_temp_new();
> > +
> > + gen_load_spr(hi, SPR_SRR0);
> > + gen_load_spr(lo, SPR_SRR1);
> > + tcg_gen_concat_tl_i64(t8, lo, hi);
> > + tcg_gen_addi_tl(EA, EA, -8);
> > + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > +
> > + gen_get_xer(ctx, hi);
> > + tcg_gen_mov_tl(lo, cpu_ctr);
> > + tcg_gen_concat_tl_i64(t8, lo, hi);
> > + tcg_gen_addi_tl(EA, EA, -8);
> > + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > +
> > + for (i = 0; i < sizeof(vd_list); i++) {
> > + int vd = vd_list[i];
> > + tcg_gen_concat_tl_i64(t8, cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd]);
> > + tcg_gen_addi_tl(EA, EA, -8);
> > + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > + }
> > +
> > + gen_load_spr(lo, SPR_SPRG0);
> > + tcg_gen_extu_i32_tl(hi, cpu_crf[0]);
> > + tcg_gen_shli_tl(hi, hi, 28);
> > + tcg_gen_concat_tl_i64(t8, lo, hi);
> > + tcg_gen_addi_tl(EA, EA, -8);
> > + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > +
> > + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], a->si * 8);
> > + tcg_gen_qemu_st_i32(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) |
> > + MO_ALIGN);
> > + tcg_gen_mov_tl(cpu_gpr[a->ra], EA);
> > + return true;
> > +#endif
> > +}
> > +
> > +static bool trans_STSKU(DisasContext *ctx, arg_STSKU *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + int64_t n;
> > + TCGv base, EA;
> > + TCGv_i32 lo, hi;
> > + TCGv_i64 t8;
> > +
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > +
> > + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> > + CHECK_PPE_GPR(ctx, a->rt);
> > +
> > + if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) {
> > + gen_invalid(ctx);
> > + return true;
> > + }
> > +
> > + EA = tcg_temp_new();
> > + base = tcg_temp_new();
> > + gen_addr_register(ctx, base);
> > + tcg_gen_addi_tl(EA, base, 4);
> > + tcg_gen_qemu_st_i32(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN);
> > +
> > + gen_store_spr(SPR_PPE42_EDR, base);
> > +
> > + n = ~(a->si);
> > +
> > + t8 = tcg_temp_new_i64();
> > + if (n > 0) {
> > + hi = cpu_gpr[30];
> > + lo = cpu_gpr[31];
> > + tcg_gen_concat_i32_i64(t8, lo, hi);
> > + tcg_gen_addi_tl(EA, base, -8);
> > + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > + }
> > + if (n > 1) {
> > + hi = cpu_gpr[28];
> > + lo = cpu_gpr[29];
> > + tcg_gen_concat_i32_i64(t8, lo, hi);
> > + tcg_gen_addi_tl(EA, base, -16);
> > + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN);
> > + }
> > +
> > + tcg_gen_addi_tl(EA, base, a->si * 8);
> > + tcg_gen_qemu_st_i32(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) |
> > + MO_ALIGN);
> > + tcg_gen_mov_tl(cpu_gpr[a->ra], EA);
> > + return true;
> > +#endif
> > +}
> > +
> > +#if !defined(TARGET_PPC64)
> > +static bool do_ppe_ldst(DisasContext *ctx, int rt, int ra, TCGv displ,
> > + bool update, bool store)
> > +{
> > + TCGv ea;
> > + int rt_lo;
> > + TCGv_i64 t8;
> > +
> > + CHECK_VDR(ctx, rt);
> > + CHECK_PPE_GPR(ctx, ra);
> > + rt_lo = VDR_PAIR_REG(rt);
> > + if (update && (ra == 0 || (!store && ((ra == rt) || (ra == rt_lo))))) {
> > + gen_invalid(ctx);
> > + return true;
> > + }
> > + gen_set_access_type(ctx, ACCESS_INT);
> > +
> > + ea = do_ea_calc(ctx, ra, displ);
> > + t8 = tcg_temp_new_i64();
> > + if (store) {
> > + tcg_gen_concat_i32_i64(t8, cpu_gpr[rt_lo], cpu_gpr[rt]);
> > + tcg_gen_qemu_st_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64));
> > + } else {
> > + tcg_gen_qemu_ld_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64));
> > + tcg_gen_extr_i64_i32(cpu_gpr[rt_lo], cpu_gpr[rt], t8);
> > + }
> > + if (update) {
> > + tcg_gen_mov_tl(cpu_gpr[ra], ea);
> > + }
> > + return true;
> > +}
> > +#endif
> > +
> > +static bool trans_LVD(DisasContext *ctx, arg_LVD *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), false, false);
> > +#endif
> > +}
> > +
> > +static bool trans_LVDU(DisasContext *ctx, arg_LVDU *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), true, false);
> > +#endif
> > +}
> > +
> > +static bool trans_LVDX(DisasContext *ctx, arg_LVDX *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + CHECK_PPE_GPR(ctx, a->rb);
> > + return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, false);
> > +#endif
> > +}
> > +
> > +static bool trans_STVD(DisasContext *ctx, arg_STVD *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), false, true);
> > +#endif
> > +}
> > +
> > +static bool trans_STVDU(DisasContext *ctx, arg_STVDU *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), true, true);
> > +#endif
> > +}
> > +
> > +static bool trans_STVDX(DisasContext *ctx, arg_STVDX *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + CHECK_PPE_GPR(ctx, a->rb);
> > + return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, true);
> > +#endif
> > +}
> > +
> > +#if !defined(TARGET_PPC64)
> > +static bool do_fcb(DisasContext *ctx, TCGv ra_val, TCGv rb_val, int bix,
> > + int32_t bdx, bool s, bool px, bool lk)
> > +{
> > + TCGCond cond;
> > + uint32_t mask;
> > + TCGLabel *no_branch;
> > + target_ulong dest;
> > +
> > + /* Update CR0 */
> > + gen_op_cmp32(ra_val, rb_val, s, 0);
> > +
> > + if (lk) {
> > + gen_setlr(ctx, ctx->base.pc_next);
> > + }
> > +
> > +
> > + mask = PPC_BIT32(28 + bix);
> > + cond = (px) ? TCG_COND_TSTEQ : TCG_COND_TSTNE;
> > + no_branch = gen_new_label();
> > + dest = ctx->cia + bdx;
> > +
> > + /* Do the branch if CR0[bix] == PX */
> > + tcg_gen_brcondi_i32(cond, cpu_crf[0], mask, no_branch);
> > + gen_goto_tb(ctx, 0, dest);
> > + gen_set_label(no_branch);
> > + gen_goto_tb(ctx, 1, ctx->base.pc_next);
> > + ctx->base.is_jmp = DISAS_NORETURN;
> > + return true;
> > +}
> > +#endif
> > +
> > +#if !defined(TARGET_PPC64)
> > +static bool do_cmp_branch(DisasContext *ctx, int ra, TCGv rb_val, int bix,
> > + int32_t bdx, bool s, bool px, bool lk)
> > +{
> > + TCGv old_ra;
> > +
> > + CHECK_PPE_GPR(ctx, ra);
> > + if (bix == 3) {
> > + old_ra = tcg_temp_new();
> > + tcg_gen_mov_tl(old_ra, cpu_gpr[ra]);
> > + tcg_gen_sub_tl(cpu_gpr[ra], cpu_gpr[ra], rb_val);
> > + return do_fcb(ctx, old_ra, rb_val, 2,
> > + bdx, s, px, lk);
> > + } else {
> > + return do_fcb(ctx, cpu_gpr[ra], rb_val, bix,
> > + bdx, s, px, lk);
> > + }
> > +}
> > +#endif
> > +
> > +#if !defined(TARGET_PPC64)
> > +static bool do_mask_branch(DisasContext *ctx, int ra, TCGv mask,
> > + int32_t bdx, bool invert, bool px, bool lk,
> > + bool update)
> > +{
> > + TCGv r;
> > + CHECK_PPE_GPR(ctx, ra);
> > + if (invert) {
> > + tcg_gen_not_tl(mask, mask);
> > + }
> > +
> > + /* apply mask to ra */
> > + r = tcg_temp_new();
> > + tcg_gen_and_tl(r, cpu_gpr[ra], mask);
> > + if (update) {
> > + tcg_gen_mov_tl(cpu_gpr[ra], r);
> > + }
> > + return do_fcb(ctx, r, tcg_constant_tl(0), 2,
> > + bdx, false, px, lk);
> > +}
> > +#endif
> > +
> > +static bool trans_CMPWBC(DisasContext *ctx, arg_CMPWBC *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + CHECK_PPE_GPR(ctx, a->rb);
> > + return do_cmp_branch(ctx, a->ra, cpu_gpr[a->rb], a->bix, a->bdx,
> > + true, a->px, a->lk);
> > +#endif
> > +}
> > +
> > +static bool trans_CMPLWBC(DisasContext *ctx, arg_CMPLWBC *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + CHECK_PPE_GPR(ctx, a->rb);
> > + return do_cmp_branch(ctx, a->ra, cpu_gpr[a->rb], a->bix, a->bdx,
> > + false, a->px, a->lk);
> > +#endif
> > +}
> > +
> > +static bool trans_CMPWIBC(DisasContext *ctx, arg_CMPWIBC *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + return do_cmp_branch(ctx, a->ra, tcg_constant_tl(a->rb), a->bix, a->bdx,
> > + true, a->px, a->lk);
> > +#endif
> > +}
> > +
> > +static bool trans_BNBWI(DisasContext *ctx, arg_BNBWI *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + return do_mask_branch(ctx, a->ra, tcg_constant_tl(PPC_BIT32(a->rb)),
> > + a->bdx, false, a->px, a->lk, false);
> > +#endif
> > +}
> > +
> > +static bool trans_BNBW(DisasContext *ctx, arg_BNBW *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + TCGv mask, shift;
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + CHECK_PPE_GPR(ctx, a->rb);
> > + mask = tcg_temp_new();
> > + shift = tcg_temp_new();
> > + tcg_gen_andi_tl(shift, cpu_gpr[a->rb], 0x1f);
> > + tcg_gen_shr_tl(mask, tcg_constant_tl(0x80000000), shift);
> > + return do_mask_branch(ctx, a->ra, mask, a->bdx, false, a->px, a->lk, false);
> > +#endif
> > +}
> > +
> > +static bool trans_CLRBWIBC(DisasContext *ctx, arg_CLRBWIBC *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + return do_mask_branch(ctx, a->ra, tcg_constant_tl(PPC_BIT32(a->rb)),
> > + a->bdx, true, a->px, a->lk, true);
> > +#endif
> > +}
> > +
> > +static bool trans_CLRBWBC(DisasContext *ctx, arg_CLRBWBC *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + TCGv mask, shift;
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + CHECK_PPE_GPR(ctx, a->rb);
> > + mask = tcg_temp_new();
> > + shift = tcg_temp_new();
> > + tcg_gen_andi_tl(shift, cpu_gpr[a->rb], 0x1f);
> > + tcg_gen_shr_tl(mask, tcg_constant_tl(0x80000000), shift);
> > + return do_mask_branch(ctx, a->ra, mask, a->bdx, true, a->px, a->lk, true);
> > +#endif
> > +}
> > +
> > +#if !defined(TARGET_PPC64)
> > +static void gen_set_Rc0_i64(DisasContext *ctx, TCGv_i64 reg)
> > +{
> > + TCGv_i64 t0 = tcg_temp_new_i64();
> > + TCGv_i64 t1 = tcg_temp_new_i64();
> > + TCGv_i32 t = tcg_temp_new_i32();
> > +
> > + tcg_gen_movi_i64(t0, CRF_EQ);
> > + tcg_gen_movi_i64(t1, CRF_LT);
> > + tcg_gen_movcond_i64(TCG_COND_LT, t0, reg, tcg_constant_i64(0), t1, t0);
> > + tcg_gen_movi_i64(t1, CRF_GT);
> > + tcg_gen_movcond_i64(TCG_COND_GT, t0, reg, tcg_constant_i64(0), t1, t0);
> > + tcg_gen_extrl_i64_i32(t, t0);
> > + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
> > + tcg_gen_or_i32(cpu_crf[0], cpu_crf[0], t);
> > +}
> > +#endif
> > +
> > +#if !defined(TARGET_PPC64)
> > +static bool do_shift64(DisasContext *ctx, arg_X_rc *a, bool left)
> > +{
> > + int rt_lo, ra_lo;
> > + TCGv_i64 t0, t8;
> > +
> > + /* Check for PPE since opcode overlaps with CNTTZDM instruction */
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> > + CHECK_VDR(ctx, a->rt);
> > + CHECK_VDR(ctx, a->ra);
> > + CHECK_PPE_GPR(ctx, a->rb);
> > + rt_lo = VDR_PAIR_REG(a->rt);
> > + ra_lo = VDR_PAIR_REG(a->ra);
> > + t8 = tcg_temp_new_i64();
> > +
> > + /* AND rt with a mask that is 0 when rb >= 0x40 */
> > + t0 = tcg_temp_new_i64();
> > + tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]);
> > + tcg_gen_shli_i64(t0, t0, 0x39);
> > + tcg_gen_sari_i64(t0, t0, 0x3f);
> > +
> > + /* form 64bit value from two 32bit regs */
> > + tcg_gen_concat_tl_i64(t8, cpu_gpr[rt_lo], cpu_gpr[a->rt]);
> > +
> > + /* apply mask */
> > + tcg_gen_andc_i64(t8, t8, t0);
> > +
> > + /* do the shift */
> > + tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]);
> > + tcg_gen_andi_i64(t0, t0, 0x3f);
> > + if (left) {
> > + tcg_gen_shl_i64(t8, t8, t0);
> > + } else {
> > + tcg_gen_shr_i64(t8, t8, t0);
> > + }
> > +
> > + /* split the 64bit word back into two 32bit regs */
> > + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8);
> > +
> > + /* update CR0 if requested */
> > + if (unlikely(a->rc != 0)) {
> > + gen_set_Rc0_i64(ctx, t8);
> > + }
> > + return true;
> > +}
> > +#endif
> > +
> > +static bool trans_SRVD(DisasContext *ctx, arg_SRVD *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + return do_shift64(ctx, a, false);
> > +#endif
> > +}
> > +
> > +static bool trans_SLVD(DisasContext *ctx, arg_SLVD *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + return do_shift64(ctx, a, true);
> > +#endif
> > +}
> > +
> > +static bool trans_DCBQ(DisasContext *ctx, arg_DCBQ *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > +
> > + CHECK_PPE_GPR(ctx, a->rt);
> > + CHECK_PPE_GPR(ctx, a->ra);
> > + CHECK_PPE_GPR(ctx, a->rb);
> > +
> > + /* No cache exists, so just set RT to 0 */
> > + tcg_gen_movi_tl(cpu_gpr[a->rt], 0);
> > + return true;
> > +#endif
> > +}
> > +
> > +static bool trans_RLDIMI(DisasContext *ctx, arg_RLDIMI *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + TCGv_i64 t_rs, t_ra;
> > + int ra_lo, rs_lo;
> > + uint32_t sh = a->sh;
> > + uint32_t mb = a->mb;
> > + uint32_t me = 63 - sh;
> > +
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> > + CHECK_VDR(ctx, a->rs);
> > + CHECK_VDR(ctx, a->ra);
> > +
> > + rs_lo = VDR_PAIR_REG(a->rs);
> > + ra_lo = VDR_PAIR_REG(a->ra);
> > +
> > + t_rs = tcg_temp_new_i64();
> > + t_ra = tcg_temp_new_i64();
> > +
> > + tcg_gen_concat_tl_i64(t_rs, cpu_gpr[rs_lo], cpu_gpr[a->rs]);
> > + tcg_gen_concat_tl_i64(t_ra, cpu_gpr[ra_lo], cpu_gpr[a->ra]);
> > +
> > + if (mb <= me) {
> > + tcg_gen_deposit_i64(t_ra, t_ra, t_rs, sh, me - mb + 1);
> > + } else {
> > + uint64_t mask = mask_u64(mb, me);
> > + TCGv_i64 t1 = tcg_temp_new_i64();
> > +
> > + tcg_gen_rotli_i64(t1, t_rs, sh);
> > + tcg_gen_andi_i64(t1, t1, mask);
> > + tcg_gen_andi_i64(t_ra, t_ra, ~mask);
> > + tcg_gen_or_i64(t_ra, t_ra, t1);
> > + }
> > +
> > + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t_ra);
> > +
> > + if (unlikely(a->rc != 0)) {
> > + gen_set_Rc0_i64(ctx, t_ra);
> > + }
> > + return true;
> > +#endif
> > +}
> > +
> > +
> > +#if !defined(TARGET_PPC64)
> > +static bool gen_rldinm_i64(DisasContext *ctx, arg_MD *a, int mb, int me, int sh)
> > +{
> > + int len = me - mb + 1;
> > + int rsh = (64 - sh) & 63;
> > + int ra_lo, rs_lo;
> > + TCGv_i64 t8;
> > +
> > + if (unlikely(!is_ppe(ctx))) {
> > + return false;
> > + }
> > + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X);
> > + CHECK_VDR(ctx, a->rs);
> > + CHECK_VDR(ctx, a->ra);
> > +
> > + rs_lo = VDR_PAIR_REG(a->rs);
> > + ra_lo = VDR_PAIR_REG(a->ra);
> > + t8 = tcg_temp_new_i64();
> > + tcg_gen_concat_tl_i64(t8, cpu_gpr[rs_lo], cpu_gpr[a->rs]);
> > + if (sh != 0 && len > 0 && me == (63 - sh)) {
> > + tcg_gen_deposit_z_i64(t8, t8, sh, len);
> > + } else if (me == 63 && rsh + len <= 64) {
> > + tcg_gen_extract_i64(t8, t8, rsh, len);
> > + } else {
> > + tcg_gen_rotli_i64(t8, t8, sh);
> > + tcg_gen_andi_i64(t8, t8, mask_u64(mb, me));
> > + }
> > + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8);
> > + if (unlikely(a->rc != 0)) {
> > + gen_set_Rc0_i64(ctx, t8);
> > + }
> > + return true;
> > +}
> > +#endif
> > +
> > +static bool trans_RLDICL(DisasContext *ctx, arg_RLDICL *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + return gen_rldinm_i64(ctx, a, a->mb, 63, a->sh);
> > +#endif
> > +}
> > +
> > +static bool trans_RLDICR(DisasContext *ctx, arg_RLDICR *a)
> > +{
> > +#if defined(TARGET_PPC64)
> > + return false;
> > +#else
> > + return gen_rldinm_i64(ctx, a, 0, a->mb, a->sh);
> > +#endif
> > +}
> > +
>
> Sorry about the formatting error in the last mail, please ignore.
>
> Hey Glenn,
>
> Do you think we can make use of TRANS macros here for insns using the
> common methods. Something like :
>
> TRANS(RLDICL, gen_rldinm_i64, a->mb, 63, a->sh)
> TRANS(RLDICR, gen_rldinm_i64, 0, a->mb, a->sh)
>
> And then have gen_rldinm_i64 like :
>
> static bool gen_rldinm_i64(...)
> {
>
> #if defined(TARGET_PPC64)
> return false;
> #else
> ...
> ...
> #endif
> }
>
> Similarlly for other insns above where possible ?
> Or is there something that I'm not seeing that prevents this ??
>
> Thanks,
> Chinmay
Yes, it looks like there probably are some cases that could utilize the
TRANS* macros. I'll work on that.
Thanks,
Glenn
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2025-09-04 14:58 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-26 20:17 [PATCH v2 0/4] Add IBM PPE42 CPU support Glenn Miles
2025-08-26 20:17 ` [PATCH v2 1/4] target/ppc: Add IBM PPE42 family of processors Glenn Miles
2025-09-01 7:29 ` Cédric Le Goater
2025-09-02 16:59 ` Miles Glenn
2025-08-26 20:17 ` [PATCH v2 2/4] target/ppc: Add IBM PPE42 special instructions Glenn Miles
2025-09-04 12:24 ` Chinmay Rath
2025-09-04 12:30 ` Chinmay Rath
2025-09-04 14:56 ` Miles Glenn
2025-08-26 20:17 ` [PATCH v2 3/4] hw/ppc: Add a test machine for the IBM PPE42 CPU Glenn Miles
2025-09-01 7:25 ` Cédric Le Goater
2025-09-01 10:15 ` BALATON Zoltan
2025-09-02 16:56 ` Miles Glenn
2025-09-03 22:50 ` Miles Glenn
2025-08-26 20:17 ` [PATCH v2 4/4] tests/functional: Add test for IBM PPE42 instructions Glenn Miles
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).