diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index ebb5c22ee13e1..f334d2d9795d7 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -540,6 +540,10 @@ VCLRRB 000100 ..... ..... ..... 00111001101 @VX # VSX Load/Store Instructions +LXSD 111001 ..... ..... .............. 10 @DS +STXSD 111101 ..... ..... .............. 10 @DS +LXSSP 111001 ..... ..... .............. 11 @DS +STXSSP 111101 ..... ..... .............. 11 @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..691e8fe6c0bbe 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,18 @@ PSTFD 000001 10 0--.-- .................. \ ### VSX instructions +PLXSD 000001 00 0--.-- .................. \ + 101010 ..... ..... ................ @8LS_D + +PSTXSD 000001 00 0--.-- .................. \ + 101110 ..... ..... ................ @8LS_D + +PLXSSP 000001 00 0--.-- .................. \ + 101011 ..... ..... ................ @8LS_D + +PSTXSSP 000001 00 0--.-- .................. \ + 101111 ..... ..... ................ @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..e6a82d5f163af 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7502,49 +7502,24 @@ 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 */ static void gen_dform39(DisasContext *ctx) { - switch (ctx->opcode & 0x3) { - case 0: /* lfdp */ + if ((ctx->opcode & 0x3) == 0) { if (ctx->insns_flags2 & PPC2_ISA205) { 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); - } - break; } return gen_invalid(ctx); } -/* handles stfdp, lxv, stxsd, stxssp lxvx */ +/* Handles stfdp */ static void gen_dform3D(DisasContext *ctx) { - if ((ctx->opcode & 3) != 1) { /* DS-FORM */ - switch (ctx->opcode & 0x3) { - case 0: /* stfdp */ - if (ctx->insns_flags2 & PPC2_ISA205) { - 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); - } - break; + if ((ctx->opcode & 3) == 0) { /* DS-FORM */ + /* stfdp */ + if (ctx->insns_flags2 & PPC2_ISA205) { + return gen_stfdp(ctx); } } return gen_invalid(ctx); diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 34ebc2c3626b0..c0e93be73de38 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -288,30 +288,6 @@ VSX_VECTOR_LOAD_STORE_LENGTH(stxvl) VSX_VECTOR_LOAD_STORE_LENGTH(stxvll) #endif -#define VSX_LOAD_SCALAR_DS(name, operation) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv EA; \ - TCGv_i64 xth; \ - \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - xth = tcg_temp_new_i64(); \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_imm_index(ctx, EA, 0x03); \ - gen_qemu_##operation(ctx, xth, EA); \ - set_cpu_vsr(rD(ctx->opcode) + 32, xth, true); \ - /* NOTE: cpu_vsrl is undefined */ \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(xth); \ -} - -VSX_LOAD_SCALAR_DS(lxsd, ld64_i64) -VSX_LOAD_SCALAR_DS(lxssp, ld32fs) - #define VSX_STORE_SCALAR(name, operation) \ static void gen_##name(DisasContext *ctx) \ { \ @@ -461,30 +437,6 @@ static void gen_stxvb16x(DisasContext *ctx) tcg_temp_free_i64(xsl); } -#define VSX_STORE_SCALAR_DS(name, operation) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv EA; \ - TCGv_i64 xth; \ - \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - xth = tcg_temp_new_i64(); \ - get_cpu_vsr(xth, rD(ctx->opcode) + 32, true); \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_imm_index(ctx, EA, 0x03); \ - gen_qemu_##operation(ctx, xth, EA); \ - /* NOTE: cpu_vsrl is undefined */ \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(xth); \ -} - -VSX_STORE_SCALAR_DS(stxsd, st64_i64) -VSX_STORE_SCALAR_DS(stxssp, st32fs) - static void gen_mfvsrwz(DisasContext *ctx) { if (xS(ctx->opcode) < 32) { @@ -2270,6 +2222,102 @@ 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); +} + +static bool do_lstxssp(DisasContext *ctx, int rt, int ra, TCGv displ, bool store) +{ + TCGv ea; + TCGv_i64 xt; + + REQUIRE_VECTOR(ctx); + + xt = tcg_temp_new_i64(); + + gen_set_access_type(ctx, ACCESS_INT); + ea = do_ea_calc(ctx, ra, displ); + + if (store) { + get_cpu_vsr(xt, rt + 32, true); + gen_qemu_st32fs(ctx, xt, ea); + } else { + gen_qemu_ld32fs(ctx, xt, ea); + 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_lstxssp_DS(DisasContext *ctx, arg_D *a, bool store) +{ + return do_lstxssp(ctx, a->rt, a->ra, tcg_constant_tl(a->si), store); +} + +static bool do_plstxssp_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool store) +{ + arg_D d; + + if (!resolve_PLS_D(ctx, &d, a)) { + return true; + } + + return do_lstxssp(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, LXSSP, do_lstxssp_DS, false) +TRANS_FLAGS2(ISA300, STXSSP, do_lstxssp_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 +2326,10 @@ 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, PLXSSP, do_plstxssp_PLS_D, false) +TRANS64_FLAGS2(ISA310, PSTXSSP, do_plstxssp_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..c3a49c2c317f8 100644 --- a/tests/tcg/ppc64/Makefile.target +++ b/tests/tcg/ppc64/Makefile.target @@ -13,6 +13,16 @@ $(PPC64_TESTS): CFLAGS += -mpower8-vector PPC64_TESTS += byte_reverse PPC64_TESTS += mtfsf ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER10),) +PPC64_TESTS += plstxsd plstxssp + +plstxsd: CFLAGS += -mpower8-vector +run-plstxsd: QEMU_OPTS+=-cpu POWER10 +run-plugin-plstxsd-with-%: QEMU_OPTS+=-cpu POWER10 + +plstxssp: CFLAGS += -mpower8-vector +run-plstxssp: QEMU_OPTS+=-cpu POWER10 +run-plugin-plstxssp-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..c1ac849277d7b 100644 --- a/tests/tcg/ppc64le/Makefile.target +++ b/tests/tcg/ppc64le/Makefile.target @@ -10,12 +10,20 @@ endif $(PPC64LE_TESTS): CFLAGS += -mpower8-vector ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER10),) -PPC64LE_TESTS += byte_reverse +PPC64LE_TESTS += byte_reverse plstxsd plstxssp 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 + +plstxssp: CFLAGS += -mpower8-vector +run-plstxssp: QEMU_OPTS+=-cpu POWER10 +run-plugin-plstxssp-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; +} diff --git a/tests/tcg/ppc64le/plstxssp.c b/tests/tcg/ppc64le/plstxssp.c new file mode 100644 index 0000000000000..81d83af28b6b1 --- /dev/null +++ b/tests/tcg/ppc64le/plstxssp.c @@ -0,0 +1,269 @@ +/* + * Test for plxssp and pstxssp instructions, as well as lxssp and stxssp. + */ + +#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_F32(f) DPRINTF("f32: %f 0x%08x\n", f, *(uint32_t *)&f) +#define DPRINT_F64(f) DPRINTF("f64: %f 0x%016lx\n", f, *(uint64_t *)&f) + +#define DPRINT_ASF64(f) \ + do { \ + double d = (f); \ + DPRINT_F64(d); \ + } while (0) + +#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 GENEXPL(src, si) gen_ld_res(src, si) +#define GENEXPS(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 -8888.25 + +/* test data */ +static float data[4] = { 1.125, 999.99, -56.0, DATA_3 }; + +/* NOTE: dst is also used with some inline asm */ +static __int128 dst; + +/* generate expected load test result */ +static __int128 gen_ld_res(float *src, int64_t si) +{ + float f32 = *(float *)((char *)src + si); + double f64 = f32; + + return I128(*(uint64_t *)&f64, 0); +} + +/* generate expected store test result */ +static __int128 gen_st_res(float src, int64_t si) +{ + __int128 d; + char *p = (char *)&d; + + INIT_DST(&d); + *(float *)(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) + +/* Test load instruction, using a generated expected result */ +#define TEST_LD(inst, src, si) \ + TEST(inst(dst, (src), (si)), GENEXPL((src), (si))) + +/* Test store instruction, using a generated expected result */ +#define TEST_ST(inst, src, si) \ + TEST(inst(&dst, (src), (si)), GENEXPS((src), (si))) + +#define LXSSP(dst, src, si) \ + asm ("lxssp %0, %1(%2)" \ + : "=v"(dst) \ + : "i"(si), "b"(src) \ + : ) + +#define LXSSP_DISP(dst, src, si) \ + LXSSP((dst), (char *)(src) -(si), (si)) + +void test_lxssp(void) +{ + float *src = data; + + DPRINTF("%s\n", __func__); + + /* Test with small displacement values */ + TEST_LD(LXSSP, src, 0); + TEST_LD(LXSSP, src + 2, 0); + TEST_LD(LXSSP, src, 4); + TEST_LD(LXSSP, src, 8); + + /* Test with big displacement values */ + TEST(LXSSP_DISP(dst, src, 1024), GENEXPL(src, 0)); + TEST(LXSSP_DISP(dst, src, 32764), GENEXPL(src, 0)); + TEST(LXSSP_DISP(dst, src, -32768), GENEXPL(src, 0)); +} + +#define PLXSSP(dst, src, si) \ + asm ("plxssp %0, %1(%2), 0" \ + : "=v"(dst) \ + : "i"(si), "b"(src) \ + : ) + +#define PLXSSP_DISP(dst, src, si) \ + PLXSSP((dst), (char *)(src) -(si), (si)) + +#define PLXSSP_RA0(dst, si) \ + asm ("plxssp %0, %1(0), 0" \ + : "=v"(dst) \ + : "i"(si) \ + : ) + +#define PLXSSP_R1(dst, src) \ + asm ( \ + "plxssp %0, 16(0), 1\n\t" \ + "b 1f\n\t" \ + "nop\n\t" \ + ".float " STR(src) "\n\t" \ + "1: nop" \ + : "=v"(dst) \ + : \ + : ) + +void test_plxssp(void) +{ + float *src = data; + + DPRINTF("%s\n", __func__); + + /* Test with small displacement values */ + TEST_LD(PLXSSP, src, 0); + TEST_LD(PLXSSP, src + 2, 0); + TEST_LD(PLXSSP, src, 4); + TEST_LD(PLXSSP, src, 8); + + /* Test with big displacement values */ + TEST(PLXSSP_DISP(dst, src, 1024), GENEXPL(src, 0)); + TEST(PLXSSP_DISP(dst, src, 32768), GENEXPL(src, 0)); + TEST(PLXSSP_DISP(dst, src, INT_MAX), GENEXPL(src, 0)); + TEST(PLXSSP_DISP(dst, src, INT_MIN), GENEXPL(src, 0)); + TEST(PLXSSP_DISP(dst, src, 8589934590), GENEXPL(src, 0)); + TEST(PLXSSP_DISP(dst, src, -8589934592), GENEXPL(src, 0)); + + /* Test with RA=0 and data passed as immediate only */ + TEST(PLXSSP_RA0(dst, data), GENEXPL(data, 0)); + + /* + * Test with R=1 (PC relative). + * DATA_3 is inserted into .text section, after tested instruction, + * and loaded into dst. + */ + TEST(PLXSSP_R1(dst, DATA_3), GENEXPL(data + 3, 0)); +} + +#define STXSSP(dst, src, si) \ + asm ("stxssp %0, %1(%2)" \ + : \ + : "v"(src), "i"(si), "b"(dst) \ + : "memory") + +#define STXSSP_DISP(dst, src, si) \ + STXSSP((char *)(dst) -(si), (src), (si)) + +void test_stxssp(void) +{ + float *src = data; + float *d = (float *)&dst; + + DPRINTF("%s\n", __func__); + + /* Test with small displacement values */ + TEST_ST(STXSSP, *src, 0); + TEST_ST(STXSSP, src[2], 0); + TEST_ST(STXSSP, *src, 4); + TEST_ST(STXSSP, *src, 8); + + /* Test with big displacement values */ + TEST(STXSSP_DISP(d, *src, 1024), GENEXPS(*src, 0)); + TEST(STXSSP_DISP(d, *src, 32764), GENEXPS(*src, 0)); + TEST(STXSSP_DISP(d, *src, -32768), GENEXPS(*src, 0)); +} + +#define PSTXSSP(dst, src, si) \ + asm ("pstxssp %0, %1(%2), 0" \ + : \ + : "v"(src), "i"(si), "b"(dst) \ + : "memory") + +#define PSTXSSP_DISP(dst, src, si) \ + PSTXSSP((char *)(dst) -(si), (src), (si)) + +#define PSTXSSP_RA0(src, si) \ + asm ("pstxssp %0, %1(0), 0" \ + : \ + : "v"(src), "i"(si) \ + : "memory") + +#define PSTXSSP_R1(dst, src) \ + asm ("0: pstxssp %0, " STR(dst) " - 0b(0), 1" \ + : \ + : "v"(src) \ + : "memory") + +void test_pstxssp(void) +{ + float *src = data; + float *d = (float *)&dst; + + DPRINTF("%s\n", __func__); + + /* Test with small displacement values */ + TEST_ST(PSTXSSP, *src, 0); + TEST_ST(PSTXSSP, src[2], 0); + TEST_ST(PSTXSSP, *src, 4); + TEST_ST(PSTXSSP, *src, 8); + + /* Test with big displacement values */ + TEST(PSTXSSP_DISP(d, *src, 1024), GENEXPS(*src, 0)); + TEST(PSTXSSP_DISP(d, *src, 32767), GENEXPS(*src, 0)); + TEST(PSTXSSP_DISP(d, *src, -32768), GENEXPS(*src, 0)); + TEST(PSTXSSP_DISP(d, *src, INT_MAX), GENEXPS(*src, 0)); + TEST(PSTXSSP_DISP(d, *src, INT_MIN), GENEXPS(*src, 0)); + TEST(PSTXSSP_DISP(d, *src, 8589934590), GENEXPS(*src, 0)); + TEST(PSTXSSP_DISP(d, *src, -8589934592), GENEXPS(*src, 0)); + + /* Test with RA=0 and dst address passed as immediate only */ + TEST(PSTXSSP_RA0(*src, &dst), GENEXPS(*src, 0)); + + /* + * Test with R=1 (PC relative). + * dst symbol is used to calculate the offset from tested instruction. + */ + TEST(PSTXSSP_R1(dst, data[3]), GENEXPS(data[3], 0)); +} + +int main(void) +{ + struct sigaction action; + + action.sa_handler = _exit; + sigaction(SIGABRT, &action, NULL); + + test_lxssp(); + test_plxssp(); + test_stxssp(); + test_pstxssp(); + + return 0; +}