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>
---
Changes from v3:
- Removed copy of CHECK_VDR
- Refactored ld/st instructions
target/ppc/insn32.decode | 66 ++-
target/ppc/translate.c | 29 +-
target/ppc/translate/ppe-impl.c.inc | 665 ++++++++++++++++++++++++++++
3 files changed, 750 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..792103d7c2
--- /dev/null
+++ b/target/ppc/translate/ppe-impl.c.inc
@@ -0,0 +1,665 @@
+/*
+ * IBM PPE Instructions
+ *
+ * Copyright (c) 2025, 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 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 disp,
+ 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, disp);
+ 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 do_ppe_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ /* Some PowerPC CPU's have a different meaning for the STVD instruction */
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update,
+ store);
+#endif
+}
+
+static bool do_ppe_ldst_X(DisasContext *ctx, arg_X *a, bool store)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ CHECK_PPE_GPR(ctx, a->rb);
+ return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, store);
+#endif
+}
+
+TRANS(LVD, do_ppe_ldst_D, false, false)
+TRANS(LVDU, do_ppe_ldst_D, true, false)
+TRANS(STVD, do_ppe_ldst_D, false, true)
+TRANS(STVDU, do_ppe_ldst_D, true, true)
+TRANS(LVDX, do_ppe_ldst_X, false)
+TRANS(STVDX, do_ppe_ldst_X, true)
+
+
+#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
+
+static bool do_cmp_branch(DisasContext *ctx, arg_FCB_bix *a, bool s,
+ bool rb_is_gpr)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ TCGv old_ra;
+ TCGv rb_val;
+
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_GPR(ctx, a->ra);
+ if (rb_is_gpr) {
+ CHECK_PPE_GPR(ctx, a->rb);
+ rb_val = cpu_gpr[a->rb];
+ } else {
+ rb_val = tcg_constant_tl(a->rb);
+ }
+ if (a->bix == 3) {
+ old_ra = tcg_temp_new();
+ tcg_gen_mov_tl(old_ra, cpu_gpr[a->ra]);
+ tcg_gen_sub_tl(cpu_gpr[a->ra], cpu_gpr[a->ra], rb_val);
+ return do_fcb(ctx, old_ra, rb_val, 2,
+ a->bdx, s, a->px, a->lk);
+ } else {
+ return do_fcb(ctx, cpu_gpr[a->ra], rb_val, a->bix,
+ a->bdx, s, a->px, a->lk);
+ }
+#endif
+}
+
+TRANS(CMPWBC, do_cmp_branch, true, true)
+TRANS(CMPLWBC, do_cmp_branch, false, true)
+TRANS(CMPWIBC, do_cmp_branch, true, false)
+
+static bool do_mask_branch(DisasContext *ctx, arg_FCB * a, bool invert,
+ bool update, bool rb_is_gpr)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ TCGv r;
+ TCGv mask, shift;
+
+ if (unlikely(!is_ppe(ctx))) {
+ return false;
+ }
+ CHECK_PPE_GPR(ctx, a->ra);
+ if (rb_is_gpr) {
+ 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);
+ } else {
+ mask = tcg_constant_tl(PPC_BIT32(a->rb));
+ }
+ if (invert) {
+ tcg_gen_not_tl(mask, mask);
+ }
+
+ /* apply mask to ra */
+ r = tcg_temp_new();
+ tcg_gen_and_tl(r, cpu_gpr[a->ra], mask);
+ if (update) {
+ tcg_gen_mov_tl(cpu_gpr[a->ra], r);
+ }
+ return do_fcb(ctx, r, tcg_constant_tl(0), 2,
+ a->bdx, false, a->px, a->lk);
+#endif
+}
+
+TRANS(BNBWI, do_mask_branch, false, false, false)
+TRANS(BNBW, do_mask_branch, false, false, true)
+TRANS(CLRBWIBC, do_mask_branch, true, true, false)
+TRANS(CLRBWBC, do_mask_branch, true, true, true)
+
+#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
+
+static bool do_shift64(DisasContext *ctx, arg_X_rc *a, bool left)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ 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
+}
+
+TRANS(SRVD, do_shift64, false)
+TRANS(SLVD, do_shift64, true)
+
+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
+}
+
+
+static bool gen_rldinm_i64(DisasContext *ctx, arg_MD *a, int mb, int me, int sh)
+{
+#if defined(TARGET_PPC64)
+ return false;
+#else
+ 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
+}
+
+TRANS(RLDICL, gen_rldinm_i64, a->mb, 63, a->sh)
+TRANS(RLDICR, gen_rldinm_i64, 0, a->mb, a->sh)
+
--
2.43.0
On 9/12/25 22:17, 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> > --- > Changes from v3: > - Removed copy of CHECK_VDR > - Refactored ld/st instructions > > target/ppc/insn32.decode | 66 ++- > target/ppc/translate.c | 29 +- > target/ppc/translate/ppe-impl.c.inc | 665 ++++++++++++++++++++++++++++ > 3 files changed, 750 insertions(+), 10 deletions(-) > create mode 100644 target/ppc/translate/ppe-impl.c.inc > <snip> > diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ppe-impl.c.inc > new file mode 100644 > index 0000000000..792103d7c2 > --- /dev/null > +++ b/target/ppc/translate/ppe-impl.c.inc > @@ -0,0 +1,665 @@ > +/* > + * IBM PPE Instructions > + * > + * Copyright (c) 2025, 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 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 If we are building the PPE42 instructions only for !TARGET_PPC64, does it still make it usable with qemu-system-ppc64? If not, we may want to use the conditional compilation in hreg_compute_hlfags_value() as well. Otherwise, we may need a run-time check to identify if its a PPC32 machine to support 32-bit machines with qemu-system-ppc64. regards, Harsh > + 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 disp, > + 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, disp); > + 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 do_ppe_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + /* Some PowerPC CPU's have a different meaning for the STVD instruction */ > + if (unlikely(!is_ppe(ctx))) { > + return false; > + } > + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, > + store); > +#endif > +} > + > +static bool do_ppe_ldst_X(DisasContext *ctx, arg_X *a, bool store) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + CHECK_PPE_GPR(ctx, a->rb); > + return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, store); > +#endif > +} > + > +TRANS(LVD, do_ppe_ldst_D, false, false) > +TRANS(LVDU, do_ppe_ldst_D, true, false) > +TRANS(STVD, do_ppe_ldst_D, false, true) > +TRANS(STVDU, do_ppe_ldst_D, true, true) > +TRANS(LVDX, do_ppe_ldst_X, false) > +TRANS(STVDX, do_ppe_ldst_X, true) > + > + > +#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 > + > +static bool do_cmp_branch(DisasContext *ctx, arg_FCB_bix *a, bool s, > + bool rb_is_gpr) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + TCGv old_ra; > + TCGv rb_val; > + > + if (unlikely(!is_ppe(ctx))) { > + return false; > + } > + CHECK_PPE_GPR(ctx, a->ra); > + if (rb_is_gpr) { > + CHECK_PPE_GPR(ctx, a->rb); > + rb_val = cpu_gpr[a->rb]; > + } else { > + rb_val = tcg_constant_tl(a->rb); > + } > + if (a->bix == 3) { > + old_ra = tcg_temp_new(); > + tcg_gen_mov_tl(old_ra, cpu_gpr[a->ra]); > + tcg_gen_sub_tl(cpu_gpr[a->ra], cpu_gpr[a->ra], rb_val); > + return do_fcb(ctx, old_ra, rb_val, 2, > + a->bdx, s, a->px, a->lk); > + } else { > + return do_fcb(ctx, cpu_gpr[a->ra], rb_val, a->bix, > + a->bdx, s, a->px, a->lk); > + } > +#endif > +} > + > +TRANS(CMPWBC, do_cmp_branch, true, true) > +TRANS(CMPLWBC, do_cmp_branch, false, true) > +TRANS(CMPWIBC, do_cmp_branch, true, false) > + > +static bool do_mask_branch(DisasContext *ctx, arg_FCB * a, bool invert, > + bool update, bool rb_is_gpr) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + TCGv r; > + TCGv mask, shift; > + > + if (unlikely(!is_ppe(ctx))) { > + return false; > + } > + CHECK_PPE_GPR(ctx, a->ra); > + if (rb_is_gpr) { > + 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); > + } else { > + mask = tcg_constant_tl(PPC_BIT32(a->rb)); > + } > + if (invert) { > + tcg_gen_not_tl(mask, mask); > + } > + > + /* apply mask to ra */ > + r = tcg_temp_new(); > + tcg_gen_and_tl(r, cpu_gpr[a->ra], mask); > + if (update) { > + tcg_gen_mov_tl(cpu_gpr[a->ra], r); > + } > + return do_fcb(ctx, r, tcg_constant_tl(0), 2, > + a->bdx, false, a->px, a->lk); > +#endif > +} > + > +TRANS(BNBWI, do_mask_branch, false, false, false) > +TRANS(BNBW, do_mask_branch, false, false, true) > +TRANS(CLRBWIBC, do_mask_branch, true, true, false) > +TRANS(CLRBWBC, do_mask_branch, true, true, true) > + > +#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 > + > +static bool do_shift64(DisasContext *ctx, arg_X_rc *a, bool left) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + 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 > +} > + > +TRANS(SRVD, do_shift64, false) > +TRANS(SLVD, do_shift64, true) > + > +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 > +} > + > + > +static bool gen_rldinm_i64(DisasContext *ctx, arg_MD *a, int mb, int me, int sh) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + 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 > +} > + > +TRANS(RLDICL, gen_rldinm_i64, a->mb, 63, a->sh) > +TRANS(RLDICR, gen_rldinm_i64, 0, a->mb, a->sh) > +
On 17/09/2025 06.57, Harsh Prateek Bora wrote: > > > On 9/12/25 22:17, 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> >> --- >> Changes from v3: >> - Removed copy of CHECK_VDR >> - Refactored ld/st instructions >> >> target/ppc/insn32.decode | 66 ++- >> target/ppc/translate.c | 29 +- >> target/ppc/translate/ppe-impl.c.inc | 665 ++++++++++++++++++++++++++++ >> 3 files changed, 750 insertions(+), 10 deletions(-) >> create mode 100644 target/ppc/translate/ppe-impl.c.inc >> > > <snip> > >> diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ >> ppe-impl.c.inc >> new file mode 100644 >> index 0000000000..792103d7c2 >> --- /dev/null >> +++ b/target/ppc/translate/ppe-impl.c.inc >> @@ -0,0 +1,665 @@ >> +/* >> + * IBM PPE Instructions >> + * >> + * Copyright (c) 2025, 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 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 > > If we are building the PPE42 instructions only for !TARGET_PPC64, does > it still make it usable with qemu-system-ppc64? As explained in an earlier thread already, qemu-system-ppc64 is a superset of qemu-system-ppc. Thus the ppe42 stuff should work in qemu-system-ppc64, too. Thomas
On Wed, 2025-09-17 at 08:20 +0200, Thomas Huth wrote: > On 17/09/2025 06.57, Harsh Prateek Bora wrote: > > > > On 9/12/25 22:17, 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> > > > --- > > > Changes from v3: > > > - Removed copy of CHECK_VDR > > > - Refactored ld/st instructions > > > > > > target/ppc/insn32.decode | 66 ++- > > > target/ppc/translate.c | 29 +- > > > target/ppc/translate/ppe-impl.c.inc | 665 ++++++++++++++++++++++++++++ > > > 3 files changed, 750 insertions(+), 10 deletions(-) > > > create mode 100644 target/ppc/translate/ppe-impl.c.inc > > > > > > > <snip> > > > > > diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ > > > ppe-impl.c.inc > > > new file mode 100644 > > > index 0000000000..792103d7c2 > > > --- /dev/null > > > +++ b/target/ppc/translate/ppe-impl.c.inc > > > @@ -0,0 +1,665 @@ > > > +/* > > > + * IBM PPE Instructions > > > + * > > > + * Copyright (c) 2025, 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 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 > > > > If we are building the PPE42 instructions only for !TARGET_PPC64, does > > it still make it usable with qemu-system-ppc64? > > As explained in an earlier thread already, qemu-system-ppc64 is a superset > of qemu-system-ppc. Thus the ppe42 stuff should work in qemu-system-ppc64, too. > > Thomas > Ah, yes, I don't think I fully understood the ramifications of Thomas's statements earlier. Looks like I'll need to scrub the code to ensure that PPE42 can run even if TARGET_PPC64 is defined. Cedric, this requires me to change my response to your request to add the check for TARGET_PPC64 inside the is_ppe() function. I will need to leave that function as-is if we want PPE42 to be supported in both targets. Will you be ok with that? Thanks, Glenn
On 9/17/25 16:38, Miles Glenn wrote: > On Wed, 2025-09-17 at 08:20 +0200, Thomas Huth wrote: >> On 17/09/2025 06.57, Harsh Prateek Bora wrote: >>> >>> On 9/12/25 22:17, 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> >>>> --- >>>> Changes from v3: >>>> - Removed copy of CHECK_VDR >>>> - Refactored ld/st instructions >>>> >>>> target/ppc/insn32.decode | 66 ++- >>>> target/ppc/translate.c | 29 +- >>>> target/ppc/translate/ppe-impl.c.inc | 665 ++++++++++++++++++++++++++++ >>>> 3 files changed, 750 insertions(+), 10 deletions(-) >>>> create mode 100644 target/ppc/translate/ppe-impl.c.inc >>>> >>> >>> <snip> >>> >>>> diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ >>>> ppe-impl.c.inc >>>> new file mode 100644 >>>> index 0000000000..792103d7c2 >>>> --- /dev/null >>>> +++ b/target/ppc/translate/ppe-impl.c.inc >>>> @@ -0,0 +1,665 @@ >>>> +/* >>>> + * IBM PPE Instructions >>>> + * >>>> + * Copyright (c) 2025, 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 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 >>> >>> If we are building the PPE42 instructions only for !TARGET_PPC64, does >>> it still make it usable with qemu-system-ppc64? >> >> As explained in an earlier thread already, qemu-system-ppc64 is a superset >> of qemu-system-ppc. Thus the ppe42 stuff should work in qemu-system-ppc64, too. >> >> Thomas >> > > Ah, yes, I don't think I fully understood the ramifications of Thomas's > statements earlier. Looks like I'll need to scrub the code to ensure > that PPE42 can run even if TARGET_PPC64 is defined. > > Cedric, this requires me to change my response to your request to add > the check for TARGET_PPC64 inside the is_ppe() function. I will need > to leave that function as-is if we want PPE42 to be supported in both > targets. Will you be ok with that? sure if it compiles. Try a clang build. C.
On Wed, 17 Sep 2025, Miles Glenn wrote: > On Wed, 2025-09-17 at 08:20 +0200, Thomas Huth wrote: >> On 17/09/2025 06.57, Harsh Prateek Bora wrote: >>> >>> On 9/12/25 22:17, 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> >>>> --- >>>> Changes from v3: >>>> - Removed copy of CHECK_VDR >>>> - Refactored ld/st instructions >>>> >>>> target/ppc/insn32.decode | 66 ++- >>>> target/ppc/translate.c | 29 +- >>>> target/ppc/translate/ppe-impl.c.inc | 665 ++++++++++++++++++++++++++++ >>>> 3 files changed, 750 insertions(+), 10 deletions(-) >>>> create mode 100644 target/ppc/translate/ppe-impl.c.inc >>>> >>> >>> <snip> >>> >>>> diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ >>>> ppe-impl.c.inc >>>> new file mode 100644 >>>> index 0000000000..792103d7c2 >>>> --- /dev/null >>>> +++ b/target/ppc/translate/ppe-impl.c.inc >>>> @@ -0,0 +1,665 @@ >>>> +/* >>>> + * IBM PPE Instructions >>>> + * >>>> + * Copyright (c) 2025, 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 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 >>> >>> If we are building the PPE42 instructions only for !TARGET_PPC64, does >>> it still make it usable with qemu-system-ppc64? >> >> As explained in an earlier thread already, qemu-system-ppc64 is a superset >> of qemu-system-ppc. Thus the ppe42 stuff should work in qemu-system-ppc64, too. >> >> Thomas >> > > Ah, yes, I don't think I fully understood the ramifications of Thomas's > statements earlier. Looks like I'll need to scrub the code to ensure > that PPE42 can run even if TARGET_PPC64 is defined. > > Cedric, this requires me to change my response to your request to add > the check for TARGET_PPC64 inside the is_ppe() function. I will need > to leave that function as-is if we want PPE42 to be supported in both > targets. Will you be ok with that? Does it make sense to support it with !TARGET_PPC64 if its only use is in qemu-system-ppc64? Even if the CPU is 32-bit it has some 64-bit instructions IIUC so does that make it TARGET_PPC64 only? Regards, BALATON Zoltan
On 17/09/2025 18.07, BALATON Zoltan wrote: > On Wed, 17 Sep 2025, Miles Glenn wrote: >> On Wed, 2025-09-17 at 08:20 +0200, Thomas Huth wrote: >>> On 17/09/2025 06.57, Harsh Prateek Bora wrote: >>>> >>>> On 9/12/25 22:17, 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> >>>>> --- >>>>> Changes from v3: >>>>> - Removed copy of CHECK_VDR >>>>> - Refactored ld/st instructions >>>>> >>>>> target/ppc/insn32.decode | 66 ++- >>>>> target/ppc/translate.c | 29 +- >>>>> target/ppc/translate/ppe-impl.c.inc | 665 ++++++++++++++++++++++++++++ >>>>> 3 files changed, 750 insertions(+), 10 deletions(-) >>>>> create mode 100644 target/ppc/translate/ppe-impl.c.inc >>>>> >>>> >>>> <snip> >>>> >>>>> diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ >>>>> ppe-impl.c.inc >>>>> new file mode 100644 >>>>> index 0000000000..792103d7c2 >>>>> --- /dev/null >>>>> +++ b/target/ppc/translate/ppe-impl.c.inc >>>>> @@ -0,0 +1,665 @@ >>>>> +/* >>>>> + * IBM PPE Instructions >>>>> + * >>>>> + * Copyright (c) 2025, 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 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 >>>> >>>> If we are building the PPE42 instructions only for !TARGET_PPC64, does >>>> it still make it usable with qemu-system-ppc64? >>> >>> As explained in an earlier thread already, qemu-system-ppc64 is a superset >>> of qemu-system-ppc. Thus the ppe42 stuff should work in qemu-system- >>> ppc64, too. >>> >>> Thomas >>> >> >> Ah, yes, I don't think I fully understood the ramifications of Thomas's >> statements earlier. Looks like I'll need to scrub the code to ensure >> that PPE42 can run even if TARGET_PPC64 is defined. >> >> Cedric, this requires me to change my response to your request to add >> the check for TARGET_PPC64 inside the is_ppe() function. I will need >> to leave that function as-is if we want PPE42 to be supported in both >> targets. Will you be ok with that? > > Does it make sense to support it with !TARGET_PPC64 if its only use is in > qemu-system-ppc64? Even if the CPU is 32-bit it has some 64-bit instructions > IIUC so does that make it TARGET_PPC64 only? As long as the GPRs are 32 bit only (which is the case here, I assume), it's a 32-bit PPC CPU, isn't it? So that certainly should not go into the ppc64 binary only. Thomas
On Wed, 2025-09-17 at 18:43 +0200, Thomas Huth wrote: > On 17/09/2025 18.07, BALATON Zoltan wrote: > > On Wed, 17 Sep 2025, Miles Glenn wrote: > > > On Wed, 2025-09-17 at 08:20 +0200, Thomas Huth wrote: > > > > On 17/09/2025 06.57, Harsh Prateek Bora wrote: > > > > > On 9/12/25 22:17, 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> > > > > > > --- > > > > > > Changes from v3: > > > > > > - Removed copy of CHECK_VDR > > > > > > - Refactored ld/st instructions > > > > > > > > > > > > target/ppc/insn32.decode | 66 ++- > > > > > > target/ppc/translate.c | 29 +- > > > > > > target/ppc/translate/ppe-impl.c.inc | 665 ++++++++++++++++++++++++++++ > > > > > > 3 files changed, 750 insertions(+), 10 deletions(-) > > > > > > create mode 100644 target/ppc/translate/ppe-impl.c.inc > > > > > > > > > > > > > > > > <snip> > > > > > > > > > > > diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ > > > > > > ppe-impl.c.inc > > > > > > new file mode 100644 > > > > > > index 0000000000..792103d7c2 > > > > > > --- /dev/null > > > > > > +++ b/target/ppc/translate/ppe-impl.c.inc > > > > > > @@ -0,0 +1,665 @@ > > > > > > +/* > > > > > > + * IBM PPE Instructions > > > > > > + * > > > > > > + * Copyright (c) 2025, 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 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 > > > > > > > > > > If we are building the PPE42 instructions only for !TARGET_PPC64, does > > > > > it still make it usable with qemu-system-ppc64? > > > > > > > > As explained in an earlier thread already, qemu-system-ppc64 is a superset > > > > of qemu-system-ppc. Thus the ppe42 stuff should work in qemu-system- > > > > ppc64, too. > > > > > > > > Thomas > > > > > > > > > > Ah, yes, I don't think I fully understood the ramifications of Thomas's > > > statements earlier. Looks like I'll need to scrub the code to ensure > > > that PPE42 can run even if TARGET_PPC64 is defined. > > > > > > Cedric, this requires me to change my response to your request to add > > > the check for TARGET_PPC64 inside the is_ppe() function. I will need > > > to leave that function as-is if we want PPE42 to be supported in both > > > targets. Will you be ok with that? > > > > Does it make sense to support it with !TARGET_PPC64 if its only use is in > > qemu-system-ppc64? Even if the CPU is 32-bit it has some 64-bit instructions > > IIUC so does that make it TARGET_PPC64 only? > > As long as the GPRs are 32 bit only (which is the case here, I assume), it's > a 32-bit PPC CPU, isn't it? So that certainly should not go into the ppc64 > binary only. > > Thomas > I agree. While the PPE42 does support some 64 bit operations, it actually is using two 32 bit register pairs to accomplish the 64 bit operations. Also, the address space is a 32 bit space. Glenn
On 9/12/25 18: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> > --- > Changes from v3: > - Removed copy of CHECK_VDR > - Refactored ld/st instructions > > target/ppc/insn32.decode | 66 ++- > target/ppc/translate.c | 29 +- > target/ppc/translate/ppe-impl.c.inc | 665 ++++++++++++++++++++++++++++ > 3 files changed, 750 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) is_ppe() needs to be conditionnaly compiled if !TARGET_PPC64 Thanks, C. > +{ > + 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..792103d7c2 > --- /dev/null > +++ b/target/ppc/translate/ppe-impl.c.inc > @@ -0,0 +1,665 @@ > +/* > + * IBM PPE Instructions > + * > + * Copyright (c) 2025, 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 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 disp, > + 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, disp); > + 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 do_ppe_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + /* Some PowerPC CPU's have a different meaning for the STVD instruction */ > + if (unlikely(!is_ppe(ctx))) { > + return false; > + } > + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, > + store); > +#endif > +} > + > +static bool do_ppe_ldst_X(DisasContext *ctx, arg_X *a, bool store) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + CHECK_PPE_GPR(ctx, a->rb); > + return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, store); > +#endif > +} > + > +TRANS(LVD, do_ppe_ldst_D, false, false) > +TRANS(LVDU, do_ppe_ldst_D, true, false) > +TRANS(STVD, do_ppe_ldst_D, false, true) > +TRANS(STVDU, do_ppe_ldst_D, true, true) > +TRANS(LVDX, do_ppe_ldst_X, false) > +TRANS(STVDX, do_ppe_ldst_X, true) > + > + > +#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 > + > +static bool do_cmp_branch(DisasContext *ctx, arg_FCB_bix *a, bool s, > + bool rb_is_gpr) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + TCGv old_ra; > + TCGv rb_val; > + > + if (unlikely(!is_ppe(ctx))) { > + return false; > + } > + CHECK_PPE_GPR(ctx, a->ra); > + if (rb_is_gpr) { > + CHECK_PPE_GPR(ctx, a->rb); > + rb_val = cpu_gpr[a->rb]; > + } else { > + rb_val = tcg_constant_tl(a->rb); > + } > + if (a->bix == 3) { > + old_ra = tcg_temp_new(); > + tcg_gen_mov_tl(old_ra, cpu_gpr[a->ra]); > + tcg_gen_sub_tl(cpu_gpr[a->ra], cpu_gpr[a->ra], rb_val); > + return do_fcb(ctx, old_ra, rb_val, 2, > + a->bdx, s, a->px, a->lk); > + } else { > + return do_fcb(ctx, cpu_gpr[a->ra], rb_val, a->bix, > + a->bdx, s, a->px, a->lk); > + } > +#endif > +} > + > +TRANS(CMPWBC, do_cmp_branch, true, true) > +TRANS(CMPLWBC, do_cmp_branch, false, true) > +TRANS(CMPWIBC, do_cmp_branch, true, false) > + > +static bool do_mask_branch(DisasContext *ctx, arg_FCB * a, bool invert, > + bool update, bool rb_is_gpr) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + TCGv r; > + TCGv mask, shift; > + > + if (unlikely(!is_ppe(ctx))) { > + return false; > + } > + CHECK_PPE_GPR(ctx, a->ra); > + if (rb_is_gpr) { > + 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); > + } else { > + mask = tcg_constant_tl(PPC_BIT32(a->rb)); > + } > + if (invert) { > + tcg_gen_not_tl(mask, mask); > + } > + > + /* apply mask to ra */ > + r = tcg_temp_new(); > + tcg_gen_and_tl(r, cpu_gpr[a->ra], mask); > + if (update) { > + tcg_gen_mov_tl(cpu_gpr[a->ra], r); > + } > + return do_fcb(ctx, r, tcg_constant_tl(0), 2, > + a->bdx, false, a->px, a->lk); > +#endif > +} > + > +TRANS(BNBWI, do_mask_branch, false, false, false) > +TRANS(BNBW, do_mask_branch, false, false, true) > +TRANS(CLRBWIBC, do_mask_branch, true, true, false) > +TRANS(CLRBWBC, do_mask_branch, true, true, true) > + > +#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 > + > +static bool do_shift64(DisasContext *ctx, arg_X_rc *a, bool left) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + 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 > +} > + > +TRANS(SRVD, do_shift64, false) > +TRANS(SLVD, do_shift64, true) > + > +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 > +} > + > + > +static bool gen_rldinm_i64(DisasContext *ctx, arg_MD *a, int mb, int me, int sh) > +{ > +#if defined(TARGET_PPC64) > + return false; > +#else > + 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 > +} > + > +TRANS(RLDICL, gen_rldinm_i64, a->mb, 63, a->sh) > +TRANS(RLDICR, gen_rldinm_i64, 0, a->mb, a->sh) > +
© 2016 - 2025 Red Hat, Inc.