aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2020-06-25 15:34:08 -0700
committerGitHub <noreply@github.com>2020-06-25 15:34:08 -0700
commit944704e224e534d5371fe6da246552c7f7fe831a (patch)
treee8f6e64c2b8f0f4779ae7ef0e44285b28e12b6ea
parentfbe74f48e16be28a2b360e8a9e845b01d9e4b167 (diff)
downloadriscv-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
-rwxr-xr-xdebug/gdbserver.py62
-rw-r--r--debug/programs/vectors.S159
-rw-r--r--debug/targets.py2
-rw-r--r--debug/testlib.py35
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",