diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index ebb5c22ee13e1..5151439d12075 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -540,6 +540,8 @@ VCLRRB 000100 ..... ..... ..... 00111001101 @VX # VSX Load/Store Instructions +LXSD 111001 ..... ..... .............. 10 @DS +STXSD 111101 ..... ..... .............. 10 @DS LXV 111101 ..... ..... ............ . 001 @DQ_TSX STXV 111101 ..... ..... ............ . 101 @DQ_TSX LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP diff --git a/target/ppc/insn64.decode b/target/ppc/insn64.decode index fdb859f62dd89..b7426f5b24811 100644 --- a/target/ppc/insn64.decode +++ b/target/ppc/insn64.decode @@ -32,6 +32,10 @@ ...... ..... ra:5 ................ \ &PLS_D si=%pls_si rt=%rt_tsxp +@8LS_D ...... .. . .. r:1 .. .................. \ + ...... rt:5 ra:5 ................ \ + &PLS_D si=%pls_si + # Format 8RR:D %8rr_si 32:s16 0:16 %8rr_xt 16:1 21:5 @@ -180,6 +184,12 @@ PSTFD 000001 10 0--.-- .................. \ ### VSX instructions +PLXSD 000001 00 0--.-- .................. \ + 101010 ..... ..... ................ @8LS_D + +PSTXSD 000001 00 0--.-- .................. \ + 101110 ..... ..... ................ @8LS_D + PLXV 000001 00 0--.-- .................. \ 11001 ...... ..... ................ @8LS_D_TSX PSTXV 000001 00 0--.-- .................. \ diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 4731a2e45ac4d..a4c4240e2a13d 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7502,7 +7502,7 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a) #include "translate/branch-impl.c.inc" -/* Handles lfdp, lxsd, lxssp */ +/* Handles lfdp, lxssp */ static void gen_dform39(DisasContext *ctx) { switch (ctx->opcode & 0x3) { @@ -7511,11 +7511,6 @@ static void gen_dform39(DisasContext *ctx) return gen_lfdp(ctx); } break; - case 2: /* lxsd */ - if (ctx->insns_flags2 & PPC2_ISA300) { - return gen_lxsd(ctx); - } - break; case 3: /* lxssp */ if (ctx->insns_flags2 & PPC2_ISA300) { return gen_lxssp(ctx); @@ -7525,7 +7520,7 @@ static void gen_dform39(DisasContext *ctx) return gen_invalid(ctx); } -/* handles stfdp, lxv, stxsd, stxssp lxvx */ +/* handles stfdp, lxv, stxssp lxvx */ static void gen_dform3D(DisasContext *ctx) { if ((ctx->opcode & 3) != 1) { /* DS-FORM */ @@ -7535,11 +7530,6 @@ static void gen_dform3D(DisasContext *ctx) return gen_stfdp(ctx); } break; - case 2: /* stxsd */ - if (ctx->insns_flags2 & PPC2_ISA300) { - return gen_stxsd(ctx); - } - break; case 3: /* stxssp */ if (ctx->insns_flags2 & PPC2_ISA300) { return gen_stxssp(ctx); diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 34ebc2c3626b0..67fbc53e9b30a 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -309,7 +309,6 @@ static void gen_##name(DisasContext *ctx) \ tcg_temp_free_i64(xth); \ } -VSX_LOAD_SCALAR_DS(lxsd, ld64_i64) VSX_LOAD_SCALAR_DS(lxssp, ld32fs) #define VSX_STORE_SCALAR(name, operation) \ @@ -482,7 +481,6 @@ static void gen_##name(DisasContext *ctx) \ tcg_temp_free_i64(xth); \ } -VSX_STORE_SCALAR_DS(stxsd, st64_i64) VSX_STORE_SCALAR_DS(stxssp, st32fs) static void gen_mfvsrwz(DisasContext *ctx) @@ -2270,6 +2268,57 @@ static bool do_lstxv_X(DisasContext *ctx, arg_X *a, bool store, bool paired) return do_lstxv(ctx, a->ra, cpu_gpr[a->rb], a->rt, store, paired); } +static bool do_lstxsd(DisasContext *ctx, int rt, int ra, TCGv displ, bool store) +{ + TCGv ea; + TCGv_i64 xt; + MemOp mop; + + if (store) { + REQUIRE_VECTOR(ctx); + } else { + REQUIRE_VSX(ctx); + } + + xt = tcg_temp_new_i64(); + mop = DEF_MEMOP(MO_UQ); + + gen_set_access_type(ctx, ACCESS_INT); + ea = do_ea_calc(ctx, ra, displ); + + if (store) { + get_cpu_vsr(xt, rt + 32, true); + tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop); + } else { + tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop); + set_cpu_vsr(rt + 32, xt, true); + set_cpu_vsr(rt + 32, tcg_constant_i64(0), false); + } + + tcg_temp_free(ea); + tcg_temp_free_i64(xt); + + return true; +} + +static bool do_lstxsd_DS(DisasContext *ctx, arg_D *a, bool store) +{ + return do_lstxsd(ctx, a->rt, a->ra, tcg_constant_tl(a->si), store); +} + +static bool do_plstxsd_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool store) +{ + arg_D d; + + if (!resolve_PLS_D(ctx, &d, a)) { + return true; + } + + return do_lstxsd(ctx, d.rt, d.ra, tcg_constant_tl(d.si), store); +} + +TRANS_FLAGS2(ISA300, LXSD, do_lstxsd_DS, false) +TRANS_FLAGS2(ISA300, STXSD, do_lstxsd_DS, true) TRANS_FLAGS2(ISA300, STXV, do_lstxv_D, true, false) TRANS_FLAGS2(ISA300, LXV, do_lstxv_D, false, false) TRANS_FLAGS2(ISA310, STXVP, do_lstxv_D, true, true) @@ -2278,6 +2327,8 @@ TRANS_FLAGS2(ISA300, STXVX, do_lstxv_X, true, false) TRANS_FLAGS2(ISA300, LXVX, do_lstxv_X, false, false) TRANS_FLAGS2(ISA310, STXVPX, do_lstxv_X, true, true) TRANS_FLAGS2(ISA310, LXVPX, do_lstxv_X, false, true) +TRANS64_FLAGS2(ISA310, PLXSD, do_plstxsd_PLS_D, false) +TRANS64_FLAGS2(ISA310, PSTXSD, do_plstxsd_PLS_D, true) TRANS64_FLAGS2(ISA310, PSTXV, do_lstxv_PLS_D, true, false) TRANS64_FLAGS2(ISA310, PLXV, do_lstxv_PLS_D, false, false) TRANS64_FLAGS2(ISA310, PSTXVP, do_lstxv_PLS_D, true, true) diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target index 0368007028c9a..ebdb48f56bf4b 100644 --- a/tests/tcg/ppc64/Makefile.target +++ b/tests/tcg/ppc64/Makefile.target @@ -13,6 +13,12 @@ $(PPC64_TESTS): CFLAGS += -mpower8-vector PPC64_TESTS += byte_reverse PPC64_TESTS += mtfsf ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER10),) +PPC64_TESTS += plstxsd + +plstxsd: CFLAGS += -mpower8-vector +run-plstxsd: QEMU_OPTS+=-cpu POWER10 +run-plugin-plstxsd-with-%: QEMU_OPTS+=-cpu POWER10 + run-byte_reverse: QEMU_OPTS+=-cpu POWER10 run-plugin-byte_reverse-with-%: QEMU_OPTS+=-cpu POWER10 else diff --git a/tests/tcg/ppc64le/Makefile.target b/tests/tcg/ppc64le/Makefile.target index 480ff0898d7ea..c4745923e23c4 100644 --- a/tests/tcg/ppc64le/Makefile.target +++ b/tests/tcg/ppc64le/Makefile.target @@ -10,12 +10,16 @@ endif $(PPC64LE_TESTS): CFLAGS += -mpower8-vector ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER10),) -PPC64LE_TESTS += byte_reverse +PPC64LE_TESTS += byte_reverse plstxsd endif byte_reverse: CFLAGS += -mcpu=power10 run-byte_reverse: QEMU_OPTS+=-cpu POWER10 run-plugin-byte_reverse-with-%: QEMU_OPTS+=-cpu POWER10 +plstxsd: CFLAGS += -mpower8-vector +run-plstxsd: QEMU_OPTS+=-cpu POWER10 +run-plugin-plstxsd-with-%: QEMU_OPTS+=-cpu POWER10 + PPC64LE_TESTS += mtfsf PPC64LE_TESTS += signal_save_restore_xer diff --git a/tests/tcg/ppc64le/plstxsd.c b/tests/tcg/ppc64le/plstxsd.c new file mode 100644 index 0000000000000..f3359b3c5b5f0 --- /dev/null +++ b/tests/tcg/ppc64le/plstxsd.c @@ -0,0 +1,235 @@ +/* + * Test for plxsd and pstxsd instructions, as well as lxsd and stxsd. + */ + +#include +#include +#include +#include +#include + +/* debug stuff */ +/* #define TEST_DEBUG */ +#ifdef TEST_DEBUG +#include +#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else +#define DPRINTF(fmt, ...) do { ; } while(0) +#endif + +#define DPRINT_I128(i) DPRINTF("0x%016lx%016lx\n", \ + (uint64_t)((i) >> 64), (uint64_t)(i)) + +/* helper macros */ +#define STR2(x) #x +#define STR(x) STR2(x) +#define I128(a, b) ((__int128)(a) << 64 | (b)) + +#define GENEXP(src, si) gen_st_res(src, si) + +/* initial value of destination */ +#define DST_INIT 0xaaaaaaaaaaaaaaaa +#define INIT_DST(dst) *dst = I128(DST_INIT, DST_INIT) +/* data[3] value, for use with asm */ +#define DATA_3 0x4041424344454647 + +/* test data */ +static int64_t data[4] = { + 0x1011121314151617, 0x2021222324252627, + 0x3031323334353637, DATA_3 }; + +/* NOTE: dst is also used with some inline asm */ +static __int128 dst; + +/* generate expected store test result */ +static __int128 gen_st_res(int64_t src, int64_t si) +{ + __int128 d; + char *p = (char *)&d; + + INIT_DST(&d); + *(int64_t *)(p + si) = src; + + return d; +} + +/* Run instruction and check if dst matches expected value */ +#define TEST(inst, exp) \ + do { \ + INIT_DST(&dst); \ + inst; \ + DPRINT_I128(dst); \ + assert(dst == exp); \ + } while (0) + +#define LXSD(dst, src, si) \ + asm ("lxsd %0, %1(%2)" \ + : "=v"(dst) \ + : "i"(si), "b"(src) \ + : ) + +#define LXSD_DISP(dst, src, si) \ + LXSD((dst), (char *)(src) -(si), (si)) + +void test_lxsd(void) +{ + int64_t *src = data; + + /* Test with small displacement values */ + TEST(LXSD(dst, src, 0), I128(*src, 0)); + TEST(LXSD(dst, src + 2, 0), I128(src[2], 0)); + TEST(LXSD(dst, src, 4), I128(*(int64_t *)((char *)src + 4), 0)); + TEST(LXSD(dst, src, 8), I128(src[1], 0)); + + /* Test with big displacement values */ + TEST(LXSD_DISP(dst, src, 1024), I128(*src, 0)); + TEST(LXSD_DISP(dst, src, 32764), I128(*src, 0)); + TEST(LXSD_DISP(dst, src, -32768), I128(*src, 0)); +} + +#define PLXSD(dst, src, si) \ + asm ("plxsd %0, %1(%2), 0" \ + : "=v"(dst) \ + : "i"(si), "b"(src) \ + : ) + +#define PLXSD_DISP(dst, src, si) \ + PLXSD((dst), (char *)(src) -(si), (si)) + +#define PLXSD_RA0(dst, si) \ + asm ("plxsd %0, %1(0), 0" \ + : "=v"(dst) \ + : "i"(si) \ + : ) + +#define PLXSD_R1(dst, src) \ + asm ( \ + "plxsd %0, 16(0), 1\n\t" \ + "b 1f\n\t" \ + "nop\n\t" \ + ".quad " STR(src) "\n\t" \ + "1: nop" \ + : "=v"(dst) \ + : \ + : ) + +void test_plxsd(void) +{ + int64_t *src = data; + + /* Test with small displacement values */ + TEST(PLXSD(dst, src, 0), I128(*src, 0)); + TEST(PLXSD(dst, src + 2, 0), I128(src[2], 0)); + TEST(PLXSD(dst, src, 4), I128(*(int64_t *)((char *)src + 4), 0)); + TEST(PLXSD(dst, src, 8), I128(src[1], 0)); + + /* Test with big displacement values */ + TEST(PLXSD_DISP(dst, src, 1024), I128(src[0], 0)); + TEST(PLXSD_DISP(dst, src, 32768), I128(src[0], 0)); + TEST(PLXSD_DISP(dst, src, INT_MAX), I128(src[0], 0)); + TEST(PLXSD_DISP(dst, src, INT_MIN), I128(src[0], 0)); + TEST(PLXSD_DISP(dst, src, 8589934590), I128(src[0], 0)); + TEST(PLXSD_DISP(dst, src, -8589934592), I128(src[0], 0)); + + /* Test with RA=0 and data passed as immediate only */ + TEST(PLXSD_RA0(dst, data), I128(data[0], 0)); + + /* + * Test with R=1 (PC relative). + * DATA_3 is inserted into .text section, after tested instruction, + * and loaded into dst. + */ + TEST(PLXSD_R1(dst, DATA_3), I128(data[3], 0)); +} + +#define STXSD(dst, src, si) \ + asm ("stxsd %0, %1(%2)" \ + : \ + : "v"(src), "i"(si), "b"(dst) \ + : "memory") + +#define STXSD_DISP(dst, src, si) \ + STXSD((char *)(dst) -(si), (src), (si)) + +void test_stxsd(void) +{ + int64_t *src = data; + int64_t *d = (int64_t *)&dst; + + /* Test with small displacement values */ + TEST(STXSD(d, *src, 0), GENEXP(*src, 0)); + TEST(STXSD(d, src[2], 0), GENEXP(src[2], 0)); + TEST(STXSD(d, *src, 4), GENEXP(*src, 4)); + TEST(STXSD(d, *src, 8), GENEXP(*src, 8)); + + /* Test with big displacement values */ + TEST(STXSD_DISP(d, *src, 1024), GENEXP(*src, 0)); + TEST(STXSD_DISP(d, *src, 32764), GENEXP(*src, 0)); + TEST(STXSD_DISP(d, *src, -32768), GENEXP(*src, 0)); +} + +#define PSTXSD(dst, src, si) \ + asm ("pstxsd %0, %1(%2), 0" \ + : \ + : "v"(src), "i"(si), "b"(dst) \ + : "memory") + +#define PSTXSD_DISP(dst, src, si) \ + PSTXSD((char *)(dst) -(si), (src), (si)) + +#define PSTXSD_RA0(src, si) \ + asm ("pstxsd %0, %1(0), 0" \ + : \ + : "v"(src), "i"(si) \ + : "memory") + +#define PSTXSD_R1(dst, src) \ + asm ("0: pstxsd %0, " STR(dst) " - 0b(0), 1" \ + : \ + : "v"(src) \ + : "memory") + +void test_pstxsd(void) +{ + int64_t *src = data; + int64_t *d = (int64_t *)&dst; + + /* Test with small displacement values */ + TEST(PSTXSD(d, *src, 0), GENEXP(*src, 0)); + TEST(PSTXSD(d, src[2], 0), GENEXP(src[2], 0)); + TEST(PSTXSD(d, *src, 4), GENEXP(*src, 4)); + TEST(PSTXSD(d, *src, 8), GENEXP(*src, 8)); + + /* Test with big displacement values */ + TEST(PSTXSD_DISP(d, *src, 1024), GENEXP(*src, 0)); + TEST(PSTXSD_DISP(d, *src, 32767), GENEXP(*src, 0)); + TEST(PSTXSD_DISP(d, *src, -32768), GENEXP(*src, 0)); + TEST(PSTXSD_DISP(d, *src, INT_MAX), GENEXP(*src, 0)); + TEST(PSTXSD_DISP(d, *src, INT_MIN), GENEXP(*src, 0)); + TEST(PSTXSD_DISP(d, *src, 8589934590), GENEXP(*src, 0)); + TEST(PSTXSD_DISP(d, *src, -8589934592), GENEXP(*src, 0)); + + /* Test with RA=0 and dst address passed as immediate only */ + TEST(PSTXSD_RA0(*src, &dst), GENEXP(*src, 0)); + + /* + * Test with R=1 (PC relative). + * dst symbol is used to calculate the offset from tested instruction. + */ + TEST(PSTXSD_R1(dst, data[3]), GENEXP(data[3], 0)); +} + +int main(void) +{ + struct sigaction action; + + action.sa_handler = _exit; + sigaction(SIGABRT, &action, NULL); + + test_lxsd(); + test_plxsd(); + test_stxsd(); + test_pstxsd(); + + return 0; +}