From: Paul Mackerras Date: Mon, 14 Sep 2020 08:21:27 +0000 (+1000) Subject: tests: Add tests for lq/stq and lqarx/stqcx. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ec5730a75acb935bd61013f72b80dd82323a6fdb;p=microwatt.git tests: Add tests for lq/stq and lqarx/stqcx. Lq and stq are tested in both BE and LE modes (though only 64-bit mode) by the 'modes' test. Lqarx and stqcx. are tested by the 'reservation' test in LE mode mode (64-bit). Signed-off-by: Paul Mackerras --- diff --git a/tests/modes/head.S b/tests/modes/head.S index d9e69dc..8b00bdd 100644 --- a/tests/modes/head.S +++ b/tests/modes/head.S @@ -230,3 +230,63 @@ restore: ld %r0,16(%r1) mtlr %r0 blr + + .global do_lq +do_lq: + lq %r6,0(%r3) + std %r6,0(%r4) + std %r7,8(%r4) + li %r3,0 + blr + + .global do_lq_np /* "non-preferred" form of lq */ +do_lq_np: + mr %r7,%r3 + lq %r6,0(%r7) + std %r6,0(%r4) + std %r7,8(%r4) + li %r3,0 + blr + + .global do_lq_bad /* illegal form of lq */ +do_lq_bad: + mr %r6,%r3 + .long 0xe0c60000 /* lq %r6,0(%r6) */ + std %r6,0(%r4) + std %r7,8(%r4) + li %r3,0 + blr + + .global do_stq +do_stq: + ld %r8,0(%r4) + ld %r9,8(%r4) + stq %r8,0(%r3) + li %r3,0 + blr + + /* big-endian versions of the above */ + .global do_lq_be +do_lq_be: + .long 0x0000c3e0 + .long 0x0000c4f8 + .long 0x0800e4f8 + .long 0x00006038 + .long 0x2000804e + + .global do_lq_np_be /* "non-preferred" form of lq */ +do_lq_np_be: + .long 0x781b677c + .long 0x0000c7e0 + .long 0x0000c4f8 + .long 0x0800e4f8 + .long 0x00006038 + .long 0x2000804e + + .global do_stq_be +do_stq_be: + .long 0x000004e9 + .long 0x080024e9 + .long 0x020003f9 + .long 0x00006038 + .long 0x2000804e diff --git a/tests/modes/modes.c b/tests/modes/modes.c index 5d0c870..c8ec9ce 100644 --- a/tests/modes/modes.c +++ b/tests/modes/modes.c @@ -12,6 +12,14 @@ extern unsigned long callit(unsigned long arg1, unsigned long arg2, unsigned long fn, unsigned long msr); +extern void do_lq(void *src, unsigned long *regs); +extern void do_lq_np(void *src, unsigned long *regs); +extern void do_lq_bad(void *src, unsigned long *regs); +extern void do_stq(void *dst, unsigned long *regs); +extern void do_lq_be(void *src, unsigned long *regs); +extern void do_lq_np_be(void *src, unsigned long *regs); +extern void do_stq_be(void *dst, unsigned long *regs); + static inline void do_tlbie(unsigned long rb, unsigned long rs) { __asm__ volatile("tlbie %0,%1" : : "r" (rb), "r" (rs) : "memory"); @@ -24,6 +32,7 @@ static inline void do_tlbie(unsigned long rb, unsigned long rs) #define PID 48 #define SPRG0 272 #define SPRG1 273 +#define SPRG3 275 #define PRTBL 720 static inline unsigned long mfspr(int sprnum) @@ -290,6 +299,167 @@ int mode_test_6(void) return 0; } +int mode_test_7(void) +{ + unsigned long quad[4] __attribute__((__aligned__(16))); + unsigned long regs[2]; + unsigned long ret, msr; + + /* + * Test lq/stq in LE mode + */ + msr = MSR_SF | MSR_LE; + quad[0] = 0x123456789abcdef0ul; + quad[1] = 0xfafa5959bcbc3434ul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_lq, msr); + if (ret) + return ret | 1; + if (regs[0] != quad[1] || regs[1] != quad[0]) + return 2; + /* unaligned may give alignment interrupt */ + quad[2] = 0x0011223344556677ul; + ret = callit((unsigned long)&quad[1], (unsigned long)regs, + (unsigned long)&do_lq, msr); + if (ret == 0) { + if (regs[0] != quad[2] || regs[1] != quad[1]) + return 3; + } else if (ret == 0x600) { + if (mfspr(SPRG0) != (unsigned long) &do_lq || + mfspr(DAR) != (unsigned long) &quad[1]) + return ret | 4; + } else + return ret | 5; + + /* try stq */ + regs[0] = 0x5238523852385238ul; + regs[1] = 0x5239523952395239ul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_stq, msr); + if (ret) + return ret | 5; + if (quad[0] != regs[1] || quad[1] != regs[0]) + return 6; + regs[0] = 0x0172686966746564ul; + regs[1] = 0xfe8d0badd00dabcdul; + ret = callit((unsigned long)quad + 1, (unsigned long)regs, + (unsigned long)&do_stq, msr); + if (ret) + return ret | 7; + if (((quad[0] >> 8) | (quad[1] << 56)) != regs[1] || + ((quad[1] >> 8) | (quad[2] << 56)) != regs[0]) + return 8; + + /* try lq non-preferred form */ + quad[0] = 0x56789abcdef01234ul; + quad[1] = 0x5959bcbc3434fafaul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_lq_np, msr); + if (ret) + return ret | 9; + if (regs[0] != quad[1] || regs[1] != quad[0]) + return 10; + /* unaligned should give alignment interrupt in uW implementation */ + quad[2] = 0x6677001122334455ul; + ret = callit((unsigned long)&quad[1], (unsigned long)regs, + (unsigned long)&do_lq_np, msr); + if (ret == 0x600) { + if (mfspr(SPRG0) != (unsigned long) &do_lq_np + 4 || + mfspr(DAR) != (unsigned long) &quad[1]) + return ret | 11; + } else + return 12; + + /* make sure lq with rt = ra causes an illegal instruction interrupt */ + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_lq_bad, msr); + if (ret != 0x700) + return 13; + if (mfspr(SPRG0) != (unsigned long)&do_lq_bad + 4 || + !(mfspr(SPRG3) & 0x80000)) + return 14; + return 0; +} + +int mode_test_8(void) +{ + unsigned long quad[4] __attribute__((__aligned__(16))); + unsigned long regs[2]; + unsigned long ret, msr; + + /* + * Test lq/stq in BE mode + */ + msr = MSR_SF; + quad[0] = 0x123456789abcdef0ul; + quad[1] = 0xfafa5959bcbc3434ul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_lq_be, msr); + if (ret) + return ret | 1; + if (regs[0] != quad[0] || regs[1] != quad[1]) { + print_hex(regs[0], 16); + print_string(" "); + print_hex(regs[1], 16); + print_string(" "); + return 2; + } + /* don't expect alignment interrupt */ + quad[2] = 0x0011223344556677ul; + ret = callit((unsigned long)&quad[1], (unsigned long)regs, + (unsigned long)&do_lq_be, msr); + if (ret == 0) { + if (regs[0] != quad[1] || regs[1] != quad[2]) + return 3; + } else + return ret | 5; + + /* try stq */ + regs[0] = 0x5238523852385238ul; + regs[1] = 0x5239523952395239ul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_stq_be, msr); + if (ret) + return ret | 5; + if (quad[0] != regs[0] || quad[1] != regs[1]) + return 6; + regs[0] = 0x0172686966746564ul; + regs[1] = 0xfe8d0badd00dabcdul; + ret = callit((unsigned long)quad + 1, (unsigned long)regs, + (unsigned long)&do_stq_be, msr); + if (ret) + return ret | 7; + if (((quad[0] >> 8) | (quad[1] << 56)) != regs[0] || + ((quad[1] >> 8) | (quad[2] << 56)) != regs[1]) { + print_hex(quad[0], 16); + print_string(" "); + print_hex(quad[1], 16); + print_string(" "); + print_hex(quad[2], 16); + print_string(" "); + return 8; + } + + /* try lq non-preferred form */ + quad[0] = 0x56789abcdef01234ul; + quad[1] = 0x5959bcbc3434fafaul; + ret = callit((unsigned long)quad, (unsigned long)regs, + (unsigned long)&do_lq_np_be, msr); + if (ret) + return ret | 9; + if (regs[0] != quad[0] || regs[1] != quad[1]) + return 10; + /* unaligned should not give alignment interrupt in uW implementation */ + quad[2] = 0x6677001122334455ul; + ret = callit((unsigned long)&quad[1], (unsigned long)regs, + (unsigned long)&do_lq_np_be, msr); + if (ret) + return ret | 11; + if (regs[0] != quad[1] || regs[1] != quad[2]) + return 12; + return 0; +} + int fail = 0; void do_test(int num, int (*test)(void)) @@ -334,6 +504,8 @@ int main(void) do_test(4, mode_test_4); do_test(5, mode_test_5); do_test(6, mode_test_6); + do_test(7, mode_test_7); + do_test(8, mode_test_8); return fail; } diff --git a/tests/reservation/head.S b/tests/reservation/head.S index ce258b5..4ff85ce 100644 --- a/tests/reservation/head.S +++ b/tests/reservation/head.S @@ -155,3 +155,31 @@ call_ret: ld %r31,248(%r1) addi %r1,%r1,256 blr + + .global do_lqarx +do_lqarx: + /* r3 = src, r4 = regs */ + lqarx %r10,0,%r3 + std %r10,0(%r4) + std %r11,8(%r4) + li %r3,0 + blr + + .global do_lqarx_bad +do_lqarx_bad: + /* r3 = src, r4 = regs */ + .long 0x7d405228 /* lqarx %r10,0,%r10 */ + std %r10,0(%r4) + std %r11,8(%r4) + li %r3,0 + blr + + .global do_stqcx +do_stqcx: + /* r3 = dest, r4 = regs, return CR */ + ld %r10,0(%r4) + ld %r11,8(%r4) + stqcx. %r10,0,%r3 + mfcr %r3 + oris %r3,%r3,1 /* to distinguish from trap number */ + blr diff --git a/tests/reservation/reservation.c b/tests/reservation/reservation.c index 280d76f..4df4511 100644 --- a/tests/reservation/reservation.c +++ b/tests/reservation/reservation.c @@ -7,6 +7,10 @@ extern unsigned long callit(unsigned long arg1, unsigned long arg2, unsigned long (*fn)(unsigned long, unsigned long)); +extern unsigned long do_lqarx(unsigned long src, unsigned long regs); +extern unsigned long do_lqarx_bad(unsigned long src, unsigned long regs); +extern unsigned long do_stqcx(unsigned long dst, unsigned long regs); + #define DSISR 18 #define DAR 19 #define SRR0 26 @@ -161,7 +165,7 @@ int resv_test_2(void) size = 1 << j; for (offset = 0; offset < 16; ++offset) { ret = callit(size, (unsigned long)&x[0] + offset, do_larx); - if (0 && ret == 0 && (offset & (size - 1)) != 0) + if (ret == 0 && (offset & (size - 1)) != 0) return j + 1; if (ret == 0x600) { if ((offset & (size - 1)) == 0) @@ -181,6 +185,63 @@ int resv_test_2(void) return 0; } +/* test lqarx/stqcx */ +int resv_test_3(void) +{ + unsigned long x[4] __attribute__((__aligned__(16))); + unsigned long y[2], regs[2]; + unsigned long ret, offset; + int count; + + x[0] = 0x7766554433221100ul; + x[1] = 0xffeeddccbbaa9988ul; + y[0] = 0x0badcafef00dd00dul; + y[1] = 0xdeadbeef07070707ul; + for (count = 0; count < 1000; ++count) { + ret = callit((unsigned long)x, (unsigned long)regs, do_lqarx); + if (ret) + return ret | 1; + ret = callit((unsigned long)x, (unsigned long)y, do_stqcx); + if (ret < 0x10000) + return ret | 2; + if (ret & 0x20000000) + break; + } + if (count == 1000) + return 3; + if (x[0] != y[1] || x[1] != y[0]) + return 4; + if (regs[1] != 0x7766554433221100ul || regs[0] != 0xffeeddccbbaa9988ul) + return 5; + ret = callit((unsigned long)x, (unsigned long)regs, do_stqcx); + if (ret < 0x10000 || (ret & 0x20000000)) + return ret | 12; + /* test alignment interrupts */ + for (offset = 0; offset < 16; ++offset) { + ret = callit((unsigned long)x + offset, (unsigned long)regs, do_lqarx); + if (ret == 0 && (offset & 15) != 0) + return 6; + if (ret == 0x600) { + if ((offset & 15) == 0) + return ret + 7; + } else if (ret) + return ret; + ret = callit((unsigned long)x + offset, (unsigned long)y, do_stqcx); + if (ret >= 0x10000 && (offset & 15) != 0) + return 8; + if (ret == 0x600) { + if ((offset & 15) == 0) + return ret + 9; + } else if (ret < 0x10000) + return ret; + } + /* test illegal interrupt for bad lqarx case */ + ret = callit((unsigned long)x, (unsigned long)regs, do_lqarx_bad); + if (ret != 0x700 || !(mfspr(SRR1) & 0x80000)) + return ret + 10; + return 0; +} + int fail = 0; void do_test(int num, int (*test)(void)) @@ -205,6 +266,7 @@ int main(void) do_test(1, resv_test_1); do_test(2, resv_test_2); + do_test(3, resv_test_3); return fail; } diff --git a/tests/test_modes.bin b/tests/test_modes.bin index 0c52628..edbe0c8 100755 Binary files a/tests/test_modes.bin and b/tests/test_modes.bin differ diff --git a/tests/test_modes.console_out b/tests/test_modes.console_out index a49bb9b..25e791c 100644 --- a/tests/test_modes.console_out +++ b/tests/test_modes.console_out @@ -4,3 +4,5 @@ test 03:PASS test 04:PASS test 05:PASS test 06:PASS +test 07:PASS +test 08:PASS diff --git a/tests/test_reservation.bin b/tests/test_reservation.bin index 31d3c8c..1e305f4 100755 Binary files a/tests/test_reservation.bin and b/tests/test_reservation.bin differ diff --git a/tests/test_reservation.console_out b/tests/test_reservation.console_out index 0c39ae3..623335d 100644 --- a/tests/test_reservation.console_out +++ b/tests/test_reservation.console_out @@ -1,2 +1,3 @@ test 01:PASS test 02:PASS +test 03:PASS