diff options
author | Tim Newsome <tim@sifive.com> | 2020-06-25 15:34:08 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-25 15:34:08 -0700 |
commit | 944704e224e534d5371fe6da246552c7f7fe831a (patch) | |
tree | e8f6e64c2b8f0f4779ae7ef0e44285b28e12b6ea /debug | |
parent | fbe74f48e16be28a2b360e8a9e845b01d9e4b167 (diff) | |
download | riscv-tests-944704e224e534d5371fe6da246552c7f7fe831a.zip riscv-tests-944704e224e534d5371fe6da246552c7f7fe831a.tar.gz riscv-tests-944704e224e534d5371fe6da246552c7f7fe831a.tar.bz2 |
Create a more sophisticated vector test (#284)
* WIP
* WIP
* Vector test seems to work well with spike.
* Check a0 in case the program didn't work right.
* Return not applicable if compile doesn't support V
Diffstat (limited to 'debug')
-rwxr-xr-x | debug/gdbserver.py | 62 | ||||
-rw-r--r-- | debug/programs/vectors.S | 159 | ||||
-rw-r--r-- | debug/targets.py | 2 | ||||
-rw-r--r-- | debug/testlib.py | 35 |
4 files changed, 248 insertions, 10 deletions
diff --git a/debug/gdbserver.py b/debug/gdbserver.py index dd9e129..4bbdd13 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -14,7 +14,7 @@ import testlib from testlib import assertEqual, assertNotEqual, assertIn, assertNotIn from testlib import assertGreater, assertRegex, assertLess from testlib import GdbTest, GdbSingleHartTest, TestFailed -from testlib import assertTrue, TestNotApplicable +from testlib import assertTrue, TestNotApplicable, CompileError MSTATUS_UIE = 0x00000001 MSTATUS_SIE = 0x00000002 @@ -1389,6 +1389,66 @@ class Sv48Test(TranslateTest): self.gdb.p("vms=&sv48") self.test_translation() +class VectorTest(GdbSingleHartTest): + compile_args = ("programs/vectors.S", ) + + def early_applicable(self): + if not self.hart.extensionSupported('V'): + return False + # If the compiler can't build this test, say it's not applicable. At + # some time all compilers will support the V extension, but we're not + # there yet. + try: + self.compile() + except CompileError as e: + if b"Error: unknown CSR `vlenb'" in e.stderr: + return False + return True + + def setup(self): + self.gdb.load() + self.gdb.b("main") + self.gdb.c() + + def test(self): + vlenb = self.gdb.p("$vlenb") + self.gdb.command("delete") + self.gdb.b("_exit") + self.gdb.b("trap_entry") + + self.gdb.b("test0") + + output = self.gdb.c() + assertIn("Breakpoint", output) + assertIn("test0", output) + + assertEqual(self.gdb.p("$a0"), 0) + a = self.gdb.x("&a", 'b', vlenb) + b = self.gdb.x("&b", 'b', vlenb) + v4 = self.gdb.p("$v4") + assertEqual(a, b) + assertEqual(b, v4["b"]) + assertEqual(0, self.gdb.p("$a0")) + + self.gdb.b("test1") + + output = self.gdb.c() + assertIn("Breakpoint", output) + assertIn("test1", output) + + assertEqual(self.gdb.p("$a0"), 0) + b = self.gdb.x("&b", 'b', vlenb) + c = self.gdb.x("&c", 'b', vlenb) + v4 = self.gdb.p("$v4") + assertEqual(b, c) + assertEqual(c, v4["b"]) + assertEqual(0, self.gdb.p("$a0")) + + output = self.gdb.c() + assertIn("Breakpoint", output) + assertIn("_exit", output) + assertEqual(self.gdb.p("status"), 0) + parsed = None def main(): parser = argparse.ArgumentParser( diff --git a/debug/programs/vectors.S b/debug/programs/vectors.S new file mode 100644 index 0000000..53e53be --- /dev/null +++ b/debug/programs/vectors.S @@ -0,0 +1,159 @@ +#include "encoding.h" + +#if XLEN == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + +#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) +#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) + + .global main + .global main_end + .global main_post_csrr + + // Load constants into all registers so we can test no register are + // clobbered after attaching. +main: + SREG ra, 0(sp) + addi sp, sp, REGBYTES + + // Set VS=1 + csrr t0, CSR_MSTATUS + li t1, set_field(0, MSTATUS_VS, 1) + or t0, t0, t1 + csrw CSR_MSTATUS, t0 + + // copy a to b + la a0, a + jal vector_load_v4 + la a0, b + jal shift_store_v4 + + // assert a == b + la a0, a + la a1, b + jal check_equal +test0: + bne a0, zero, return_from_main + + // copy b to c + la a0, b + jal shift_load_v4 + la a0, c + jal vector_store_v4 + + // assert b == c + la a0, b + la a1, c + jal check_equal +test1: + bne a0, zero, return_from_main + +return_from_main: + addi sp, sp, -REGBYTES + LREG ra, 0(sp) + ret + +vector_load_v4: + // a0: point to memory to load from + csrr s0, vlenb + vsetvli zero, s0, e8, m1 # Vectors of 8b + vle8.v v4, 0(a0) # Load bytes + ret + +vector_store_v4: + // a0: point to memory to store to + csrr s0, vlenb + vsetvli zero, s0, e8, m1 # Vectors of 8b + vse8.v v4, 0(a0) # Load bytes + ret + +shift_load_v4: + // a0: pointer to memory to load from + + // Configure all elements in the chain + csrr s0, vlenb +#if XLEN == 32 + vsetvli zero, s0, e32 +#else + vsetvli zero, s0, e64 +#endif + + // Figure out how long the chain is. + csrr s0, vlenb + li s1, XLEN/8 + divu s0, s0, s1 + +1: + LREG s2, 0(a0) + vslide1down.vx v4, v4, s2 + addi a0, a0, REGBYTES + addi s0, s0, -1 + bne s0, zero, 1b + + ret + +shift_store_v4: + // a0: pointer to memory to store to + + // Configure all elements in the chain + csrr s0, vlenb +#if XLEN == 32 + vsetvli zero, s0, e32 +#else + vsetvli zero, s0, e64 +#endif + + // Figure out how long the chain is. + csrr s0, vlenb + li s1, XLEN/8 + divu s0, s0, s1 + +1: + vmv.x.s s2, v4 + SREG s2, 0(a0) + vslide1down.vx v4, v4, s2 + addi a0, a0, REGBYTES + addi s0, s0, -1 + bne s0, zero, 1b + + ret + +check_equal: + csrr s0, vlenb +1: + lb s1, 0(a0) + lb s2, 0(a1) + bne s1, s2, 2f + addi a0, a0, 1 + addi a1, a1, 1 + addi s0, s0, -1 + bne s0, zero, 1b + li a0, 0 // equal + ret +2: // unequal + li a0, 1 + ret + + .data + .align 6 +a: .word 0xaa00, 0xaa01, 0xaa02, 0xaa03, 0xaa04, 0xaa05, 0xaa06, 0xaa07 + .word 0xaa08, 0xaa09, 0xaa0a, 0xaa0b, 0xaa0c, 0xaa0d, 0xaa0e, 0xaa0f + .word 0xaa10, 0xaa11, 0xaa12, 0xaa13, 0xaa14, 0xaa15, 0xaa16, 0xaa17 + .word 0xaa18, 0xaa19, 0xaa1a, 0xaa1b, 0xaa1c, 0xaa1d, 0xaa1e, 0xaa1f + +b: .word 0xbb00, 0xbb01, 0xbb02, 0xbb03, 0xbb04, 0xbb05, 0xbb06, 0xbb07 + .word 0xbb08, 0xbb09, 0xbb0b, 0xbb0b, 0xbb0c, 0xbb0d, 0xbb0e, 0xbb0f + .word 0xbb10, 0xbb11, 0xbb13, 0xbb13, 0xbb14, 0xbb15, 0xbb16, 0xbb17 + .word 0xbb18, 0xbb19, 0xbb1b, 0xbb1b, 0xbb1c, 0xbb1d, 0xbb1e, 0xbb1f + +c: .word 0xcc00, 0xcc01, 0xcc02, 0xcc03, 0xcc04, 0xcc05, 0xcc06, 0xcc07 + .word 0xcc08, 0xcc09, 0xcc0c, 0xcc0c, 0xcc0c, 0xcc0d, 0xcc0e, 0xcc0f + .word 0xcc10, 0xcc11, 0xcc13, 0xcc13, 0xcc14, 0xcc15, 0xcc16, 0xcc17 + .word 0xcc18, 0xcc19, 0xcc1c, 0xcc1c, 0xcc1c, 0xcc1d, 0xcc1e, 0xcc1f
\ No newline at end of file diff --git a/debug/targets.py b/debug/targets.py index 9c1ccf0..e8a606c 100644 --- a/debug/targets.py +++ b/debug/targets.py @@ -162,7 +162,7 @@ class Target: args.append("-DRV32E") else: march = "rv%dima" % hart.xlen - for letter in "fdc": + for letter in "fdcv": if hart.extensionSupported(letter): march += letter args.append("-march=%s" % march) diff --git a/debug/testlib.py b/debug/testlib.py index bd83d56..e003fdc 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -29,8 +29,18 @@ def find_file(path): return relpath return None +class CompileError(Exception): + def __init__(self, stdout, stderr): + self.stdout = stdout + self.stderr = stderr + +gcc_cmd = None def compile(args): # pylint: disable=redefined-builtin - cmd = ["riscv64-unknown-elf-gcc", "-g"] + if gcc_cmd: + cmd = [gcc_cmd] + else: + cmd = ["riscv64-unknown-elf-gcc"] + cmd.append("-g") for arg in args: found = find_file(arg) if found: @@ -43,10 +53,10 @@ def compile(args): # pylint: disable=redefined-builtin stderr=subprocess.PIPE) stdout, stderr = process.communicate() if process.returncode: - print(stdout, end=" ") - print(stderr, end=" ") + print(stdout.decode('ascii'), end=" ") + print(stderr.decode('ascii'), end=" ") header("") - raise Exception("Compile failed!") + raise CompileError(stdout, stderr) class Spike: # pylint: disable=too-many-instance-attributes @@ -666,10 +676,15 @@ class Gdb: self.select_child(child) self.interrupt() - def x(self, address, size='w'): - output = self.command("x/%s %s" % (size, address)) - value = int(output.split(':')[1].strip(), 0) - return value + def x(self, address, size='w', count=1): + output = self.command("x/%d%s %s" % (count, size, address)) + values = [] + for line in output.splitlines(): + for value in line.split(':')[1].strip().split(): + values.append(int(value, 0)) + if len(values) == 1: + return values[0] + return values def p_raw(self, obj): output = self.command("p %s" % obj) @@ -806,6 +821,8 @@ def run_all_tests(module, target, parsed): global gdb_cmd # pylint: disable=global-statement gdb_cmd = parsed.gdb + global gcc_cmd # pylint: disable=global-statement + gcc_cmd = parsed.gcc examine_added = False for hart in target.harts: @@ -889,6 +906,8 @@ def add_test_run_options(parser): help="Print out a list of tests, and exit immediately.") parser.add_argument("test", nargs='*', help="Run only tests that are named here.") + parser.add_argument("--gcc", + help="The command to use to start gcc.") parser.add_argument("--gdb", help="The command to use to start gdb.") parser.add_argument("--misaval", |