From: Aboorva Devarajan <[email protected]>
Move below instructions to decodetree specification:
lwat, stwat : X-form (word atomic, ISA 3.0)
ldat, stdat : X-form (doubleword atomic, ISA 3.0)
The legacy gen_ld_atomic()/gen_st_atomic() functions that read register
fields and the function code from ctx->opcode are replaced by new
do_ld_atomic()/do_st_atomic() helpers in fixedpoint-impl.c.inc that
use the pre-extracted decodetree argument fields (a->rt, a->ra, a->rb)
directly. The RB field carries the Function Code (FC) selecting the
atomic operation.
gen_fetch_inc_conditional() is similarly moved and refactored to accept
the destination register number as an explicit parameter instead of
extracting it from ctx->opcode.
Checked with '-d in_asm,op'. The printed TCG ops may differ from the
pre-refactor log because EA now uses do_ea_calc(ctx, ra, 0), which lowers
as GPR[ra] + 0 (then narrow in 32-bit mode) instead of mov/ext32u from ra
alone.
Signed-off-by: Aboorva Devarajan <[email protected]>
Signed-off-by: Chinmay Rath <[email protected]>
---
target/ppc/insn32.decode | 7 +
target/ppc/translate.c | 212 --------------------
target/ppc/translate/fixedpoint-impl.c.inc | 215 +++++++++++++++++++++
3 files changed, 222 insertions(+), 212 deletions(-)
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 4a28fad64b..f35f7113a0 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -343,6 +343,13 @@ LSKU 111010 ..... ..... ............. 0 11 @DD
LCXU 111010 ..... ..... ............. 1 11 @DD
+### Fixed-Point Atomic Load/Store Instructions
+
+LWAT 011111 ..... ..... ..... 1001000110 - @X
+STWAT 011111 ..... ..... ..... 1011000110 - @X
+LDAT 011111 ..... ..... ..... 1001100110 - @X
+STDAT 011111 ..... ..... ..... 1011100110 - @X
+
### Fixed-Point Store Instructions
STB 100110 ..... ..... ................ @D
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 7bfbba85d0..2345bf8867 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -2741,212 +2741,6 @@ static void gen_isync(DisasContext *ctx)
ctx->base.is_jmp = DISAS_EXIT_UPDATE;
}
-static void gen_fetch_inc_conditional(DisasContext *ctx, MemOp memop,
- TCGv EA, TCGCond cond, int addend)
-{
- TCGv t = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
- TCGv u = tcg_temp_new();
-
- tcg_gen_qemu_ld_tl(t, EA, ctx->mem_idx, memop);
- tcg_gen_addi_tl(t2, EA, memop_size(memop));
- tcg_gen_qemu_ld_tl(t2, t2, ctx->mem_idx, memop);
- tcg_gen_addi_tl(u, t, addend);
-
- /* E.g. for fetch and increment bounded... */
- /* mem(EA,s) = (t != t2 ? u = t + 1 : t) */
- tcg_gen_movcond_tl(cond, u, t, t2, u, t);
- tcg_gen_qemu_st_tl(u, EA, ctx->mem_idx, memop);
-
- /* RT = (t != t2 ? t : u = 1<<(s*8-1)) */
- tcg_gen_movcond_tl(cond, cpu_gpr[rD(ctx->opcode)], t, t2, t,
- tcg_constant_tl(1 << (memop_size(memop) * 8 - 1)));
-}
-
-static void gen_ld_atomic(DisasContext *ctx, MemOp memop)
-{
- uint32_t gpr_FC = FC(ctx->opcode);
- TCGv EA = tcg_temp_new();
- int rt = rD(ctx->opcode);
- bool need_serial;
- TCGv src, dst;
-
- gen_addr_register(ctx, EA);
- dst = cpu_gpr[rt];
- src = cpu_gpr[(rt + 1) & 31];
-
- need_serial = false;
- memop |= MO_ALIGN;
- switch (gpr_FC) {
- case 0: /* Fetch and add */
- tcg_gen_atomic_fetch_add_tl(dst, EA, src, ctx->mem_idx, memop);
- break;
- case 1: /* Fetch and xor */
- tcg_gen_atomic_fetch_xor_tl(dst, EA, src, ctx->mem_idx, memop);
- break;
- case 2: /* Fetch and or */
- tcg_gen_atomic_fetch_or_tl(dst, EA, src, ctx->mem_idx, memop);
- break;
- case 3: /* Fetch and 'and' */
- tcg_gen_atomic_fetch_and_tl(dst, EA, src, ctx->mem_idx, memop);
- break;
- case 4: /* Fetch and max unsigned */
- tcg_gen_atomic_fetch_umax_tl(dst, EA, src, ctx->mem_idx, memop);
- break;
- case 5: /* Fetch and max signed */
- tcg_gen_atomic_fetch_smax_tl(dst, EA, src, ctx->mem_idx, memop);
- break;
- case 6: /* Fetch and min unsigned */
- tcg_gen_atomic_fetch_umin_tl(dst, EA, src, ctx->mem_idx, memop);
- break;
- case 7: /* Fetch and min signed */
- tcg_gen_atomic_fetch_smin_tl(dst, EA, src, ctx->mem_idx, memop);
- break;
- case 8: /* Swap */
- tcg_gen_atomic_xchg_tl(dst, EA, src, ctx->mem_idx, memop);
- break;
-
- case 16: /* Compare and swap not equal */
- if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
- need_serial = true;
- } else {
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
-
- tcg_gen_qemu_ld_tl(t0, EA, ctx->mem_idx, memop);
- if ((memop & MO_SIZE) == MO_64 || TARGET_LONG_BITS == 32) {
- tcg_gen_mov_tl(t1, src);
- } else {
- tcg_gen_ext32u_tl(t1, src);
- }
- tcg_gen_movcond_tl(TCG_COND_NE, t1, t0, t1,
- cpu_gpr[(rt + 2) & 31], t0);
- tcg_gen_qemu_st_tl(t1, EA, ctx->mem_idx, memop);
- tcg_gen_mov_tl(dst, t0);
- }
- break;
-
- case 24: /* Fetch and increment bounded */
- if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
- need_serial = true;
- } else {
- gen_fetch_inc_conditional(ctx, memop, EA, TCG_COND_NE, 1);
- }
- break;
- case 25: /* Fetch and increment equal */
- if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
- need_serial = true;
- } else {
- gen_fetch_inc_conditional(ctx, memop, EA, TCG_COND_EQ, 1);
- }
- break;
- case 28: /* Fetch and decrement bounded */
- if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
- need_serial = true;
- } else {
- gen_fetch_inc_conditional(ctx, memop, EA, TCG_COND_NE, -1);
- }
- break;
-
- default:
- /* invoke data storage error handler */
- gen_exception_err(ctx, POWERPC_EXCP_DSI, POWERPC_EXCP_INVAL);
- }
-
- if (need_serial) {
- /* Restart with exclusive lock. */
- gen_helper_exit_atomic(tcg_env);
- ctx->base.is_jmp = DISAS_NORETURN;
- }
-}
-
-static void gen_lwat(DisasContext *ctx)
-{
- gen_ld_atomic(ctx, DEF_MEMOP(MO_UL));
-}
-
-#ifdef TARGET_PPC64
-static void gen_ldat(DisasContext *ctx)
-{
- gen_ld_atomic(ctx, DEF_MEMOP(MO_UQ));
-}
-#endif
-
-static void gen_st_atomic(DisasContext *ctx, MemOp memop)
-{
- uint32_t gpr_FC = FC(ctx->opcode);
- TCGv EA = tcg_temp_new();
- TCGv src, discard;
-
- gen_addr_register(ctx, EA);
- src = cpu_gpr[rD(ctx->opcode)];
- discard = tcg_temp_new();
-
- memop |= MO_ALIGN;
- switch (gpr_FC) {
- case 0: /* add and Store */
- tcg_gen_atomic_add_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
- break;
- case 1: /* xor and Store */
- tcg_gen_atomic_xor_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
- break;
- case 2: /* Or and Store */
- tcg_gen_atomic_or_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
- break;
- case 3: /* 'and' and Store */
- tcg_gen_atomic_and_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
- break;
- case 4: /* Store max unsigned */
- tcg_gen_atomic_umax_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
- break;
- case 5: /* Store max signed */
- tcg_gen_atomic_smax_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
- break;
- case 6: /* Store min unsigned */
- tcg_gen_atomic_umin_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
- break;
- case 7: /* Store min signed */
- tcg_gen_atomic_smin_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
- break;
- case 24: /* Store twin */
- if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
- /* Restart with exclusive lock. */
- gen_helper_exit_atomic(tcg_env);
- ctx->base.is_jmp = DISAS_NORETURN;
- } else {
- TCGv t = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
- TCGv s = tcg_temp_new();
- TCGv s2 = tcg_temp_new();
- TCGv ea_plus_s = tcg_temp_new();
-
- tcg_gen_qemu_ld_tl(t, EA, ctx->mem_idx, memop);
- tcg_gen_addi_tl(ea_plus_s, EA, memop_size(memop));
- tcg_gen_qemu_ld_tl(t2, ea_plus_s, ctx->mem_idx, memop);
- tcg_gen_movcond_tl(TCG_COND_EQ, s, t, t2, src, t);
- tcg_gen_movcond_tl(TCG_COND_EQ, s2, t, t2, src, t2);
- tcg_gen_qemu_st_tl(s, EA, ctx->mem_idx, memop);
- tcg_gen_qemu_st_tl(s2, ea_plus_s, ctx->mem_idx, memop);
- }
- break;
- default:
- /* invoke data storage error handler */
- gen_exception_err(ctx, POWERPC_EXCP_DSI, POWERPC_EXCP_INVAL);
- }
-}
-
-static void gen_stwat(DisasContext *ctx)
-{
- gen_st_atomic(ctx, DEF_MEMOP(MO_UL));
-}
-
-#ifdef TARGET_PPC64
-static void gen_stdat(DisasContext *ctx)
-{
- gen_st_atomic(ctx, DEF_MEMOP(MO_UQ));
-}
-#endif
-
/* wait */
static void gen_wait(DisasContext *ctx)
{
@@ -5608,12 +5402,6 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001,
PPC_STRING),
GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_STRING),
GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING),
GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM),
-GEN_HANDLER_E(lwat, 0x1F, 0x06, 0x12, 0x00000001, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(stwat, 0x1F, 0x06, 0x16, 0x00000001, PPC_NONE, PPC2_ISA300),
-#if defined(TARGET_PPC64)
-GEN_HANDLER_E(ldat, 0x1F, 0x06, 0x13, 0x00000001, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(stdat, 0x1F, 0x06, 0x17, 0x00000001, PPC_NONE, PPC2_ISA300),
-#endif
/* ISA v3.0 changed the extended opcode from 62 to 30 */
GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x039FF801, PPC_WAIT),
GEN_HANDLER_E(wait, 0x1F, 0x1E, 0x00, 0x039CF801, PPC_NONE, PPC2_ISA300),
diff --git a/target/ppc/translate/fixedpoint-impl.c.inc
b/target/ppc/translate/fixedpoint-impl.c.inc
index 25a60d3d3a..4d35133adc 100644
--- a/target/ppc/translate/fixedpoint-impl.c.inc
+++ b/target/ppc/translate/fixedpoint-impl.c.inc
@@ -1646,3 +1646,218 @@ static bool trans_SRAWI(DisasContext *ctx, arg_SRAWI *a)
}
return true;
}
+
+static void do_fetch_inc_conditional(DisasContext *ctx, MemOp memop,
+ TCGv EA, int rt,
+ TCGCond cond, int addend)
+{
+ TCGv t = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+ TCGv u = tcg_temp_new();
+
+ tcg_gen_qemu_ld_tl(t, EA, ctx->mem_idx, memop);
+ tcg_gen_addi_tl(t2, EA, memop_size(memop));
+ tcg_gen_qemu_ld_tl(t2, t2, ctx->mem_idx, memop);
+ tcg_gen_addi_tl(u, t, addend);
+
+ /* mem(EA,s) = (t cond t2 ? u = t + addend : t) */
+ tcg_gen_movcond_tl(cond, u, t, t2, u, t);
+ tcg_gen_qemu_st_tl(u, EA, ctx->mem_idx, memop);
+
+ /* RT = (t cond t2 ? t : 1<<(s*8-1)) */
+ tcg_gen_movcond_tl(cond, cpu_gpr[rt], t, t2, t,
+ tcg_constant_tl(1 << (memop_size(memop) * 8 - 1)));
+}
+
+/*
+ * Fixed-Point Atomic Load/Store Instructions
+ *
+ * In the X-form encoding the RB field carries the Function Code (FC)
+ * that selects the atomic operation. EA is computed from RA alone.
+ */
+static bool do_ld_atomic(DisasContext *ctx, arg_X *a, MemOp memop)
+{
+ TCGv EA, dst, src;
+ bool need_serial;
+
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+
+ EA = do_ea_calc(ctx, a->ra, tcg_constant_tl(0));
+ dst = cpu_gpr[a->rt];
+ src = cpu_gpr[(a->rt + 1) & 31];
+
+ need_serial = false;
+ memop |= MO_ALIGN;
+ switch (a->rb) {
+ case 0: /* Fetch and add */
+ tcg_gen_atomic_fetch_add_tl(dst, EA, src, ctx->mem_idx, memop);
+ break;
+ case 1: /* Fetch and xor */
+ tcg_gen_atomic_fetch_xor_tl(dst, EA, src, ctx->mem_idx, memop);
+ break;
+ case 2: /* Fetch and or */
+ tcg_gen_atomic_fetch_or_tl(dst, EA, src, ctx->mem_idx, memop);
+ break;
+ case 3: /* Fetch and 'and' */
+ tcg_gen_atomic_fetch_and_tl(dst, EA, src, ctx->mem_idx, memop);
+ break;
+ case 4: /* Fetch and max unsigned */
+ tcg_gen_atomic_fetch_umax_tl(dst, EA, src, ctx->mem_idx, memop);
+ break;
+ case 5: /* Fetch and max signed */
+ tcg_gen_atomic_fetch_smax_tl(dst, EA, src, ctx->mem_idx, memop);
+ break;
+ case 6: /* Fetch and min unsigned */
+ tcg_gen_atomic_fetch_umin_tl(dst, EA, src, ctx->mem_idx, memop);
+ break;
+ case 7: /* Fetch and min signed */
+ tcg_gen_atomic_fetch_smin_tl(dst, EA, src, ctx->mem_idx, memop);
+ break;
+ case 8: /* Swap */
+ tcg_gen_atomic_xchg_tl(dst, EA, src, ctx->mem_idx, memop);
+ break;
+
+ case 16: /* Compare and swap not equal */
+ if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
+ need_serial = true;
+ } else {
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+
+ tcg_gen_qemu_ld_tl(t0, EA, ctx->mem_idx, memop);
+ if ((memop & MO_SIZE) == MO_64 || TARGET_LONG_BITS == 32) {
+ tcg_gen_mov_tl(t1, src);
+ } else {
+ tcg_gen_ext32u_tl(t1, src);
+ }
+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t0, t1,
+ cpu_gpr[(a->rt + 2) & 31], t0);
+ tcg_gen_qemu_st_tl(t1, EA, ctx->mem_idx, memop);
+ tcg_gen_mov_tl(dst, t0);
+ }
+ break;
+
+ case 24: /* Fetch and increment bounded */
+ if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
+ need_serial = true;
+ } else {
+ do_fetch_inc_conditional(ctx, memop, EA, a->rt, TCG_COND_NE, 1);
+ }
+ break;
+ case 25: /* Fetch and increment equal */
+ if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
+ need_serial = true;
+ } else {
+ do_fetch_inc_conditional(ctx, memop, EA, a->rt, TCG_COND_EQ, 1);
+ }
+ break;
+ case 28: /* Fetch and decrement bounded */
+ if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
+ need_serial = true;
+ } else {
+ do_fetch_inc_conditional(ctx, memop, EA, a->rt, TCG_COND_NE, -1);
+ }
+ break;
+
+ default:
+ /* invoke data storage error handler */
+ gen_exception_err(ctx, POWERPC_EXCP_DSI, POWERPC_EXCP_INVAL);
+ return true;
+ }
+
+ if (need_serial) {
+ /* Restart with exclusive lock. */
+ gen_helper_exit_atomic(tcg_env);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ }
+ return true;
+}
+
+static bool do_st_atomic(DisasContext *ctx, arg_X *a, MemOp memop)
+{
+ TCGv EA, src, discard;
+
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+
+ EA = do_ea_calc(ctx, a->ra, tcg_constant_tl(0));
+ src = cpu_gpr[a->rt];
+ discard = tcg_temp_new();
+
+ memop |= MO_ALIGN;
+ switch (a->rb) {
+ case 0: /* add and Store */
+ tcg_gen_atomic_add_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
+ break;
+ case 1: /* xor and Store */
+ tcg_gen_atomic_xor_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
+ break;
+ case 2: /* Or and Store */
+ tcg_gen_atomic_or_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
+ break;
+ case 3: /* 'and' and Store */
+ tcg_gen_atomic_and_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
+ break;
+ case 4: /* Store max unsigned */
+ tcg_gen_atomic_umax_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
+ break;
+ case 5: /* Store max signed */
+ tcg_gen_atomic_smax_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
+ break;
+ case 6: /* Store min unsigned */
+ tcg_gen_atomic_umin_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
+ break;
+ case 7: /* Store min signed */
+ tcg_gen_atomic_smin_fetch_tl(discard, EA, src, ctx->mem_idx, memop);
+ break;
+ case 24: /* Store twin */
+ if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
+ /* Restart with exclusive lock. */
+ gen_helper_exit_atomic(tcg_env);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ } else {
+ TCGv t = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+ TCGv s = tcg_temp_new();
+ TCGv s2 = tcg_temp_new();
+ TCGv ea_plus_s = tcg_temp_new();
+
+ tcg_gen_qemu_ld_tl(t, EA, ctx->mem_idx, memop);
+ tcg_gen_addi_tl(ea_plus_s, EA, memop_size(memop));
+ tcg_gen_qemu_ld_tl(t2, ea_plus_s, ctx->mem_idx, memop);
+ tcg_gen_movcond_tl(TCG_COND_EQ, s, t, t2, src, t);
+ tcg_gen_movcond_tl(TCG_COND_EQ, s2, t, t2, src, t2);
+ tcg_gen_qemu_st_tl(s, EA, ctx->mem_idx, memop);
+ tcg_gen_qemu_st_tl(s2, ea_plus_s, ctx->mem_idx, memop);
+ }
+ break;
+ default:
+ /* invoke data storage error handler */
+ gen_exception_err(ctx, POWERPC_EXCP_DSI, POWERPC_EXCP_INVAL);
+ }
+ return true;
+}
+
+TRANS(LWAT, do_ld_atomic, DEF_MEMOP(MO_UL))
+TRANS(STWAT, do_st_atomic, DEF_MEMOP(MO_UL))
+
+static bool trans_LDAT(DisasContext *ctx, arg_LDAT *a)
+{
+ REQUIRE_64BIT(ctx);
+#if defined(TARGET_PPC64)
+ return do_ld_atomic(ctx, a, DEF_MEMOP(MO_UQ));
+#else
+ qemu_build_not_reached();
+#endif
+ return true;
+}
+
+static bool trans_STDAT(DisasContext *ctx, arg_STDAT *a)
+{
+ REQUIRE_64BIT(ctx);
+#if defined(TARGET_PPC64)
+ return do_st_atomic(ctx, a, DEF_MEMOP(MO_UQ));
+#else
+ qemu_build_not_reached();
+#endif
+ return true;
+}
--
2.53.0