diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2022-09-29 12:42:02 +0100 |
---|---|---|
committer | Alex Bennée <alex.bennee@linaro.org> | 2022-10-06 11:53:40 +0100 |
commit | 37b0dba45c4e44a02000a4170f25af0110f501d5 (patch) | |
tree | e8099b7134d51aa64be14cc2af845ce91cb21ef6 /tests/tcg/ppc64 | |
parent | 6ffe81370aab511f438ece256977def804f9b6e2 (diff) | |
download | qemu-37b0dba45c4e44a02000a4170f25af0110f501d5.zip qemu-37b0dba45c4e44a02000a4170f25af0110f501d5.tar.gz qemu-37b0dba45c4e44a02000a4170f25af0110f501d5.tar.bz2 |
tests/tcg: unify ppc64 and ppc64le Makefiles
Make tests/tcg/ppc64le include tests/tcg/ppc64 instead of duplicating
the rules. Because the ppc64le vpath includes tests/tcg/ppc64 but
not vice versa, the tests have to be moved from tests/tcg/ppc64le/
to tests/tcg/ppc64.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20220929114231.583801-23-alex.bennee@linaro.org>
Diffstat (limited to 'tests/tcg/ppc64')
-rw-r--r-- | tests/tcg/ppc64/Makefile.target | 1 | ||||
-rw-r--r-- | tests/tcg/ppc64/bcdsub.c | 134 | ||||
-rw-r--r-- | tests/tcg/ppc64/byte_reverse.c | 21 | ||||
-rw-r--r-- | tests/tcg/ppc64/mffsce.c | 37 | ||||
-rw-r--r-- | tests/tcg/ppc64/mtfsf.c | 60 | ||||
-rw-r--r-- | tests/tcg/ppc64/non_signalling_xscv.c | 37 | ||||
-rw-r--r-- | tests/tcg/ppc64/signal_save_restore_xer.c | 42 | ||||
-rw-r--r-- | tests/tcg/ppc64/xxspltw.c | 46 |
8 files changed, 377 insertions, 1 deletions
diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target index 331fae6..7db7a3e 100644 --- a/tests/tcg/ppc64/Makefile.target +++ b/tests/tcg/ppc64/Makefile.target @@ -3,7 +3,6 @@ # ppc64 specific tweaks VPATH += $(SRC_PATH)/tests/tcg/ppc64 -VPATH += $(SRC_PATH)/tests/tcg/ppc64le ifneq ($(CROSS_CC_HAS_POWER8_VECTOR),) PPC64_TESTS=bcdsub non_signalling_xscv diff --git a/tests/tcg/ppc64/bcdsub.c b/tests/tcg/ppc64/bcdsub.c new file mode 100644 index 0000000..87c8c44 --- /dev/null +++ b/tests/tcg/ppc64/bcdsub.c @@ -0,0 +1,134 @@ +#include <assert.h> +#include <unistd.h> +#include <signal.h> +#include <stdint.h> + +#define CRF_LT (1 << 3) +#define CRF_GT (1 << 2) +#define CRF_EQ (1 << 1) +#define CRF_SO (1 << 0) +#define UNDEF 0 + +#ifdef __has_builtin +#if !__has_builtin(__builtin_bcdsub) +#define NO_BUILTIN_BCDSUB +#endif +#endif + +#ifdef NO_BUILTIN_BCDSUB +#define BCDSUB(T, A, B, PS) \ + ".long 4 << 26 | (" #T ") << 21 | (" #A ") << 16 | (" #B ") << 11" \ + " | 1 << 10 | (" #PS ") << 9 | 65\n\t" +#else +#define BCDSUB(T, A, B, PS) "bcdsub. " #T ", " #A ", " #B ", " #PS "\n\t" +#endif + +#define TEST(AH, AL, BH, BL, PS, TH, TL, CR6) \ + do { \ + int cr = 0; \ + uint64_t th, tl; \ + /* \ + * Use GPR pairs to load the VSR values and place the resulting VSR and\ + * CR6 in th, tl, and cr. Note that we avoid newer instructions (e.g., \ + * mtvsrdd/mfvsrld) so we can run this test on POWER8 machines. \ + */ \ + asm ("mtvsrd 32, %3\n\t" \ + "mtvsrd 33, %4\n\t" \ + "xxmrghd 32, 32, 33\n\t" \ + "mtvsrd 33, %5\n\t" \ + "mtvsrd 34, %6\n\t" \ + "xxmrghd 33, 33, 34\n\t" \ + BCDSUB(0, 0, 1, PS) \ + "mfocrf %0, 0b10\n\t" \ + "mfvsrd %1, 32\n\t" \ + "xxswapd 32, 32\n\t" \ + "mfvsrd %2, 32\n\t" \ + : "=r" (cr), "=r" (th), "=r" (tl) \ + : "r" (AH), "r" (AL), "r" (BH), "r" (BL) \ + : "v0", "v1", "v2"); \ + if (TH != UNDEF || TL != UNDEF) { \ + assert(tl == TL); \ + assert(th == TH); \ + } \ + assert((cr >> 4) == CR6); \ + } while (0) + +/* + * Unbounded result is equal to zero: + * sign = (PS) ? 0b1111 : 0b1100 + * CR6 = 0b0010 + */ +void test_bcdsub_eq(void) +{ + /* maximum positive BCD value */ + TEST(0x9999999999999999, 0x999999999999999c, + 0x9999999999999999, 0x999999999999999c, + 0, 0x0, 0xc, CRF_EQ); + TEST(0x9999999999999999, 0x999999999999999c, + 0x9999999999999999, 0x999999999999999c, + 1, 0x0, 0xf, CRF_EQ); +} + +/* + * Unbounded result is greater than zero: + * sign = (PS) ? 0b1111 : 0b1100 + * CR6 = (overflow) ? 0b0101 : 0b0100 + */ +void test_bcdsub_gt(void) +{ + /* maximum positive and negative one BCD values */ + TEST(0x9999999999999999, 0x999999999999999c, 0x0, 0x1d, 0, + 0x0, 0xc, (CRF_GT | CRF_SO)); + TEST(0x9999999999999999, 0x999999999999999c, 0x0, 0x1d, 1, + 0x0, 0xf, (CRF_GT | CRF_SO)); + + TEST(0x9999999999999999, 0x999999999999998c, 0x0, 0x1d, 0, + 0x9999999999999999, 0x999999999999999c, CRF_GT); + TEST(0x9999999999999999, 0x999999999999998c, 0x0, 0x1d, 1, + 0x9999999999999999, 0x999999999999999f, CRF_GT); +} + +/* + * Unbounded result is less than zero: + * sign = 0b1101 + * CR6 = (overflow) ? 0b1001 : 0b1000 + */ +void test_bcdsub_lt(void) +{ + /* positive zero and positive one BCD values */ + TEST(0x0, 0xc, 0x0, 0x1c, 0, 0x0, 0x1d, CRF_LT); + TEST(0x0, 0xc, 0x0, 0x1c, 1, 0x0, 0x1d, CRF_LT); + + /* maximum negative and positive one BCD values */ + TEST(0x9999999999999999, 0x999999999999999d, 0x0, 0x1c, 0, + 0x0, 0xd, (CRF_LT | CRF_SO)); + TEST(0x9999999999999999, 0x999999999999999d, 0x0, 0x1c, 1, + 0x0, 0xd, (CRF_LT | CRF_SO)); +} + +void test_bcdsub_invalid(void) +{ + TEST(0x0, 0x1c, 0x0, 0xf00, 0, UNDEF, UNDEF, CRF_SO); + TEST(0x0, 0x1c, 0x0, 0xf00, 1, UNDEF, UNDEF, CRF_SO); + + TEST(0x0, 0xf00, 0x0, 0x1c, 0, UNDEF, UNDEF, CRF_SO); + TEST(0x0, 0xf00, 0x0, 0x1c, 1, UNDEF, UNDEF, CRF_SO); + + TEST(0x0, 0xbad, 0x0, 0xf00, 0, UNDEF, UNDEF, CRF_SO); + TEST(0x0, 0xbad, 0x0, 0xf00, 1, UNDEF, UNDEF, CRF_SO); +} + +int main(void) +{ + struct sigaction action; + + action.sa_handler = _exit; + sigaction(SIGABRT, &action, NULL); + + test_bcdsub_eq(); + test_bcdsub_gt(); + test_bcdsub_lt(); + test_bcdsub_invalid(); + + return 0; +} diff --git a/tests/tcg/ppc64/byte_reverse.c b/tests/tcg/ppc64/byte_reverse.c new file mode 100644 index 0000000..53b76fc --- /dev/null +++ b/tests/tcg/ppc64/byte_reverse.c @@ -0,0 +1,21 @@ +#include <assert.h> + +int main(void) +{ + unsigned long var; + + var = 0xFEDCBA9876543210; + asm("brh %0, %0" : "+r"(var)); + assert(var == 0xDCFE98BA54761032); + + var = 0xFEDCBA9876543210; + asm("brw %0, %0" : "+r"(var)); + assert(var == 0x98BADCFE10325476); + + var = 0xFEDCBA9876543210; + asm("brd %0, %0" : "+r"(var)); + assert(var == 0x1032547698BADCFE); + + return 0; +} + diff --git a/tests/tcg/ppc64/mffsce.c b/tests/tcg/ppc64/mffsce.c new file mode 100644 index 0000000..20d882c --- /dev/null +++ b/tests/tcg/ppc64/mffsce.c @@ -0,0 +1,37 @@ +#include <stdlib.h> +#include <stdint.h> +#include <assert.h> + +#define MTFSF(FLM, FRB) asm volatile ("mtfsf %0, %1" :: "i" (FLM), "f" (FRB)) +#define MFFS(FRT) asm("mffs %0" : "=f" (FRT)) +#define MFFSCE(FRT) asm("mffsce %0" : "=f" (FRT)) + +#define PPC_BIT_NR(nr) (63 - (nr)) + +#define FP_VE (1ull << PPC_BIT_NR(56)) +#define FP_UE (1ull << PPC_BIT_NR(58)) +#define FP_ZE (1ull << PPC_BIT_NR(59)) +#define FP_XE (1ull << PPC_BIT_NR(60)) +#define FP_NI (1ull << PPC_BIT_NR(61)) +#define FP_RN1 (1ull << PPC_BIT_NR(63)) + +int main(void) +{ + uint64_t frt, fpscr; + uint64_t test_value = FP_VE | FP_UE | FP_ZE | + FP_XE | FP_NI | FP_RN1; + MTFSF(0b11111111, test_value); /* set test value to cpu fpscr */ + MFFSCE(frt); + MFFS(fpscr); /* read the value that mffsce stored to cpu fpscr */ + + /* the returned value should be as the cpu fpscr was before */ + assert((frt & 0xff) == test_value); + + /* + * the cpu fpscr last 3 bits should be unchanged + * and enable bits should be unset + */ + assert((fpscr & 0xff) == (test_value & 0x7)); + + return 0; +} diff --git a/tests/tcg/ppc64/mtfsf.c b/tests/tcg/ppc64/mtfsf.c new file mode 100644 index 0000000..bed5b1a --- /dev/null +++ b/tests/tcg/ppc64/mtfsf.c @@ -0,0 +1,60 @@ +#include <stdlib.h> +#include <stdint.h> +#include <assert.h> +#include <signal.h> +#include <sys/prctl.h> + +#define MTFSF(FLM, FRB) asm volatile ("mtfsf %0, %1" :: "i" (FLM), "f" (FRB)) +#define MFFS(FRT) asm("mffs %0" : "=f" (FRT)) + +#define FPSCR_VE 7 /* Floating-point invalid operation exception enable */ +#define FPSCR_VXSOFT 10 /* Floating-point invalid operation exception (soft) */ +#define FPSCR_FI 17 /* Floating-point fraction inexact */ + +#define FP_VE (1ull << FPSCR_VE) +#define FP_VXSOFT (1ull << FPSCR_VXSOFT) +#define FP_FI (1ull << FPSCR_FI) + +void sigfpe_handler(int sig, siginfo_t *si, void *ucontext) +{ + if (si->si_code == FPE_FLTINV) { + exit(0); + } + exit(1); +} + +int main(void) +{ + uint64_t fpscr; + + struct sigaction sa = { + .sa_sigaction = sigfpe_handler, + .sa_flags = SA_SIGINFO + }; + + /* + * Enable the MSR bits F0 and F1 to enable exceptions. + * This shouldn't be needed in linux-user as these bits are enabled by + * default, but this allows to execute either in a VM or a real machine + * to compare the behaviors. + */ + prctl(PR_SET_FPEXC, PR_FP_EXC_PRECISE); + + /* First test if the FI bit is being set correctly */ + MTFSF(0b11111111, FP_FI); + MFFS(fpscr); + assert((fpscr & FP_FI) != 0); + + /* Then test if the deferred exception is being called correctly */ + sigaction(SIGFPE, &sa, NULL); + + /* + * Although the VXSOFT exception has been chosen, based on test in a Power9 + * any combination of exception bit + its enabling bit should work. + * But if a different exception is chosen si_code check should + * change accordingly. + */ + MTFSF(0b11111111, FP_VE | FP_VXSOFT); + + return 1; +} diff --git a/tests/tcg/ppc64/non_signalling_xscv.c b/tests/tcg/ppc64/non_signalling_xscv.c new file mode 100644 index 0000000..836df71 --- /dev/null +++ b/tests/tcg/ppc64/non_signalling_xscv.c @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <stdint.h> +#include <inttypes.h> +#include <assert.h> + +#define TEST(INSN, B_HI, B_LO, T_HI, T_LO) \ + do { \ + uint64_t th, tl, bh = B_HI, bl = B_LO; \ + asm("mtvsrd 32, %2\n\t" \ + "mtvsrd 33, %3\n\t" \ + "xxmrghd 32, 32, 33\n\t" \ + INSN " 32, 32\n\t" \ + "mfvsrd %0, 32\n\t" \ + "xxswapd 32, 32\n\t" \ + "mfvsrd %1, 32\n\t" \ + : "=r" (th), "=r" (tl) \ + : "r" (bh), "r" (bl) \ + : "v0", "v1"); \ + printf(INSN "(0x%016" PRIx64 "%016" PRIx64 ") = 0x%016" PRIx64 \ + "%016" PRIx64 "\n", bh, bl, th, tl); \ + assert(th == T_HI && tl == T_LO); \ + } while (0) + +int main(void) +{ + /* SNaN shouldn't be silenced */ + TEST("xscvspdpn", 0x7fbfffff00000000ULL, 0x0, 0x7ff7ffffe0000000ULL, 0x0); + TEST("xscvdpspn", 0x7ff7ffffffffffffULL, 0x0, 0x7fbfffff7fbfffffULL, 0x0); + + /* + * SNaN inputs having no significant bits in the upper 23 bits of the + * signifcand will return Infinity as the result. + */ + TEST("xscvdpspn", 0x7ff000001fffffffULL, 0x0, 0x7f8000007f800000ULL, 0x0); + + return 0; +} diff --git a/tests/tcg/ppc64/signal_save_restore_xer.c b/tests/tcg/ppc64/signal_save_restore_xer.c new file mode 100644 index 0000000..9227f4f --- /dev/null +++ b/tests/tcg/ppc64/signal_save_restore_xer.c @@ -0,0 +1,42 @@ +#include <assert.h> +#include <stdint.h> +#include <signal.h> +#include <sys/user.h> + +#define XER_SO (1 << 31) +#define XER_OV (1 << 30) +#define XER_CA (1 << 29) +#define XER_OV32 (1 << 19) +#define XER_CA32 (1 << 18) + +uint64_t saved; + +void sigtrap_handler(int sig, siginfo_t *si, void *ucontext) +{ + ucontext_t *uc = ucontext; + uc->uc_mcontext.regs->nip += 4; + saved = uc->uc_mcontext.regs->xer; + uc->uc_mcontext.regs->xer |= XER_OV | XER_OV32; +} + +int main(void) +{ + uint64_t initial = XER_CA | XER_CA32, restored; + struct sigaction sa = { + .sa_sigaction = sigtrap_handler, + .sa_flags = SA_SIGINFO + }; + + sigaction(SIGTRAP, &sa, NULL); + + asm("mtspr 1, %1\n\t" + "trap\n\t" + "mfspr %0, 1\n\t" + : "=r" (restored) + : "r" (initial)); + + assert(saved == initial); + assert(restored == (XER_OV | XER_OV32 | XER_CA | XER_CA32)); + + return 0; +} diff --git a/tests/tcg/ppc64/xxspltw.c b/tests/tcg/ppc64/xxspltw.c new file mode 100644 index 0000000..4cff78b --- /dev/null +++ b/tests/tcg/ppc64/xxspltw.c @@ -0,0 +1,46 @@ +#include <stdio.h> +#include <stdint.h> +#include <inttypes.h> +#include <assert.h> + +#define WORD_A 0xAAAAAAAAUL +#define WORD_B 0xBBBBBBBBUL +#define WORD_C 0xCCCCCCCCUL +#define WORD_D 0xDDDDDDDDUL + +#define DWORD_HI (WORD_A << 32 | WORD_B) +#define DWORD_LO (WORD_C << 32 | WORD_D) + +#define TEST(HI, LO, UIM, RES) \ + do { \ + union { \ + uint64_t u; \ + double f; \ + } h = { .u = HI }, l = { .u = LO }; \ + /* \ + * Use a pair of FPRs to load the VSR avoiding insns \ + * newer than xxswapd. \ + */ \ + asm("xxmrghd 32, %0, %1\n\t" \ + "xxspltw 32, 32, %2\n\t" \ + "xxmrghd %0, 32, %0\n\t" \ + "xxswapd 32, 32\n\t" \ + "xxmrghd %1, 32, %1\n\t" \ + : "+f" (h.f), "+f" (l.f) \ + : "i" (UIM) \ + : "v0"); \ + printf("xxspltw(0x%016" PRIx64 "%016" PRIx64 ", %d) =" \ + " %016" PRIx64 "%016" PRIx64 "\n", HI, LO, UIM, \ + h.u, l.u); \ + assert(h.u == (RES)); \ + assert(l.u == (RES)); \ + } while (0) + +int main(void) +{ + TEST(DWORD_HI, DWORD_LO, 0, WORD_A << 32 | WORD_A); + TEST(DWORD_HI, DWORD_LO, 1, WORD_B << 32 | WORD_B); + TEST(DWORD_HI, DWORD_LO, 2, WORD_C << 32 | WORD_C); + TEST(DWORD_HI, DWORD_LO, 3, WORD_D << 32 | WORD_D); + return 0; +} |