aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2020-02-14 14:54:07 -0800
committerGitHub <noreply@github.com>2020-02-14 14:54:07 -0800
commit10706c544e9bca0cf2dc3867c9d3dbb77c53fa3b (patch)
treeae4fb72db6a88e89f8634de170b194f187c551cd
parentabfa60c8c94d40d726d2f4bd03222ac8cff585aa (diff)
downloadriscv-tests-10706c544e9bca0cf2dc3867c9d3dbb77c53fa3b.zip
riscv-tests-10706c544e9bca0cf2dc3867c9d3dbb77c53fa3b.tar.gz
riscv-tests-10706c544e9bca0cf2dc3867c9d3dbb77c53fa3b.tar.bz2
Add tests for vector register access (#244)
* WIP * Add vector register smoketest. Also redo the gdb value parsing code to accommodate the more complicated way that vector registers look. * Test vector access a little more thoroughly. * Revert unnecessary changes.
-rwxr-xr-xdebug/gdbserver.py21
-rw-r--r--debug/targets/RISC-V/spike32-2-hwthread.py6
-rw-r--r--debug/targets/RISC-V/spike32.py8
-rw-r--r--debug/targets/RISC-V/spike64-2.py9
-rw-r--r--debug/testlib.py127
5 files changed, 137 insertions, 34 deletions
diff --git a/debug/gdbserver.py b/debug/gdbserver.py
index 04459b8..db339a9 100755
--- a/debug/gdbserver.py
+++ b/debug/gdbserver.py
@@ -117,6 +117,27 @@ class SimpleT1Test(SimpleRegisterTest):
def test(self):
self.check_reg("t1", "x6")
+class SimpleV13Test(SimpleRegisterTest):
+ def test(self):
+ if self.hart.extensionSupported('V'):
+ vlenb = self.gdb.p("$vlenb")
+ # Can't write quadwords, because gdb won't parse a 128-bit hex
+ # value.
+ written = {}
+ for name, byte_count in (('b', 1), ('s', 2), ('w', 4), ('l', 8)):
+ written[name] = {}
+ for i in range(vlenb // byte_count):
+ written[name][i] = random.randrange(256 ** byte_count)
+ self.gdb.p("$v13.%s[%d]=0x%x" % (name, i, written[name][i]))
+ self.gdb.stepi()
+ self.gdb.p("$v13")
+ for i in range(vlenb // byte_count):
+ assertEqual(self.gdb.p("$v13.%s[%d]" % (name, i)),
+ written[name][i])
+ else:
+ output = self.gdb.p_raw("$v13")
+ assertRegex(output, r"void|Could not fetch register.*")
+
class SimpleF18Test(SimpleRegisterTest):
def check_reg(self, name, alias):
if self.hart.extensionSupported('F'):
diff --git a/debug/targets/RISC-V/spike32-2-hwthread.py b/debug/targets/RISC-V/spike32-2-hwthread.py
index 93308fb..2ad2998 100644
--- a/debug/targets/RISC-V/spike32-2-hwthread.py
+++ b/debug/targets/RISC-V/spike32-2-hwthread.py
@@ -4,12 +4,12 @@ import testlib
import spike32 # pylint: disable=import-error
class spike32_2(targets.Target):
- harts = [spike32.spike32_hart(misa=0x40141129),
- spike32.spike32_hart(misa=0x40141129)]
+ harts = [spike32.spike32_hart(misa=0x40341101),
+ spike32.spike32_hart(misa=0x40341101)]
openocd_config_path = "spike-2-hwthread.cfg"
timeout_sec = 5
implements_custom_test = True
def create(self):
- return testlib.Spike(self, support_hasel=True,
+ return testlib.Spike(self, isa="RV32IMAV", support_hasel=True,
support_haltgroups=False)
diff --git a/debug/targets/RISC-V/spike32.py b/debug/targets/RISC-V/spike32.py
index 614c180..b261f6c 100644
--- a/debug/targets/RISC-V/spike32.py
+++ b/debug/targets/RISC-V/spike32.py
@@ -13,12 +13,14 @@ class spike32_hart(targets.Hart):
self.misa = misa
class spike32(targets.Target):
- harts = [spike32_hart(misa=0x4014112d)]
+ harts = [spike32_hart(misa=0x4034112d)]
openocd_config_path = "spike-1.cfg"
timeout_sec = 30
implements_custom_test = True
def create(self):
# 64-bit FPRs on 32-bit target
- return testlib.Spike(self, isa="RV32IMAFDC", dmi_rti=4,
- support_abstract_csr=True, support_haltgroups=False)
+ return testlib.Spike(self, isa="RV32IMAFDCV", dmi_rti=4,
+ support_abstract_csr=True, support_haltgroups=False,
+ # elen must be at least 64 because D is supported.
+ elen=64)
diff --git a/debug/targets/RISC-V/spike64-2.py b/debug/targets/RISC-V/spike64-2.py
index 6b9b5c9..5ace23b 100644
--- a/debug/targets/RISC-V/spike64-2.py
+++ b/debug/targets/RISC-V/spike64-2.py
@@ -4,8 +4,8 @@ import testlib
import spike64 # pylint: disable=import-error
class spike64_2(targets.Target):
- harts = [spike64.spike64_hart(misa=0x8000000000141129),
- spike64.spike64_hart(misa=0x8000000000141129)]
+ harts = [spike64.spike64_hart(misa=0x8000000000341129),
+ spike64.spike64_hart(misa=0x8000000000341129)]
openocd_config_path = "spike-2.cfg"
# Increased timeout because we use abstract_rti to artificially slow things
# down.
@@ -14,5 +14,6 @@ class spike64_2(targets.Target):
support_hasel = False
def create(self):
- return testlib.Spike(self, isa="RV64IMAFD", abstract_rti=30,
- support_hasel=False, support_abstract_csr=False)
+ return testlib.Spike(self, isa="RV64IMAFDV", abstract_rti=30,
+ support_hasel=False, support_abstract_csr=False,
+ vlen=512, elen=64)
diff --git a/debug/testlib.py b/debug/testlib.py
index 1a1a8a9..6f5c9d5 100644
--- a/debug/testlib.py
+++ b/debug/testlib.py
@@ -54,7 +54,7 @@ class Spike:
def __init__(self, target, halted=False, timeout=None, with_jtag_gdb=True,
isa=None, progbufsize=None, dmi_rti=None, abstract_rti=None,
support_hasel=True, support_abstract_csr=True,
- support_haltgroups=True):
+ support_haltgroups=True, vlen=128, elen=64, slen=128):
"""Launch spike. Return tuple of its process and the port it's running
on."""
self.process = None
@@ -65,6 +65,9 @@ class Spike:
self.support_abstract_csr = support_abstract_csr
self.support_hasel = support_hasel
self.support_haltgroups = support_haltgroups
+ self.vlen = vlen
+ self.elen = elen
+ self.slen = slen
if target.harts:
harts = target.harts
@@ -141,6 +144,10 @@ class Spike:
if not self.support_haltgroups:
cmd.append("--dm-no-halt-groups")
+ if 'V' in isa[2:]:
+ cmd.append("--varch=v%d:e%d:s%d" % (self.vlen, self.elen,
+ self.slen))
+
assert len(set(t.ram for t in harts)) == 1, \
"All spike harts must have the same RAM layout"
assert len(set(t.ram_size for t in harts)) == 1, \
@@ -381,29 +388,101 @@ class CouldNotFetch(Exception):
Thread = collections.namedtuple('Thread', ('id', 'description', 'target_id',
'name', 'frame'))
-def parse_rhs(text):
- text = text.strip()
- if text.startswith("{") and text.endswith("}"):
- inner = text[1:-1]
- parsed = [parse_rhs(t) for t in inner.split(", ")]
- if all([isinstance(p, dict) for p in parsed]):
- dictionary = {}
- for p in parsed:
- for k, v in p.items():
- dictionary[k] = v
- parsed = dictionary
- return parsed
- elif text.startswith('"') and text.endswith('"'):
- return text[1:-1]
- elif ' = ' in text:
- lhs, rhs = text.split(' = ', 1)
- return {lhs: parse_rhs(rhs)}
- elif re.match(r"-?(\d+\.\d+(e-?\d+)?|inf)", text):
- return float(text)
- elif re.match(r"-?nan\(0x[a-f0-9]+\)", text):
- return float("nan")
+class Repeat:
+ def __init__(self, count):
+ self.count = count
+
+def tokenize(text):
+ index = 0
+ while index < len(text):
+ int_match = re.match(r"-?\d+", text[index:])
+ float_match = re.match(r"-?\d*\.\d+(e[-+]\d+)?", text[index:])
+ nan_match = re.match(r"-?nan\(0x[a-f0-9]+\)", text)
+ hex_match = re.match(r"0x[\da-fA-F]+", text[index:])
+ whitespace_match = re.match(r"[\s]+", text[index:])
+ name_match = re.match(r"[a-zA-Z][a-zA-Z\d]*", text[index:])
+ repeat_match = re.match(r"<repeats (\d+) times>", text[index:])
+ string_match = re.match(r'"([^"]*)"', text[index:])
+ if text[index] in (",", "{", "}", "="):
+ yield text[index]
+ index += 1
+ elif nan_match:
+ index += len(nan_match.group(0))
+ yield float("nan")
+ elif float_match:
+ index += len(float_match.group(0))
+ yield float(float_match.group(0))
+ elif hex_match:
+ yield int(hex_match.group(0)[2:], 16)
+ index += len(hex_match.group(0))
+ elif int_match:
+ index += len(int_match.group(0))
+ yield int(int_match.group(0))
+ elif whitespace_match:
+ index += len(whitespace_match.group(0))
+ elif name_match:
+ index += len(name_match.group(0))
+ yield name_match.group(0)
+ elif repeat_match:
+ index += len(repeat_match.group(0))
+ yield Repeat(int(repeat_match.group(1)))
+ elif string_match:
+ # Note: no attempt is made to deal with escaped characters.
+ index += len(string_match.group(0))
+ yield string_match.group(1)
+ else:
+ raise Exception(text[index:])
+
+def parse_dict(tokens):
+ assert tokens[0] == "{"
+ tokens.pop(0)
+ result = {}
+ while True:
+ key = tokens.pop(0)
+ assert tokens.pop(0) == "="
+ value = parse_tokens(tokens)
+ result[key] = value
+ token = tokens.pop(0)
+ if token == "}":
+ return result
+ assert token == ","
+
+def parse_list(tokens):
+ assert tokens[0] == "{"
+ tokens.pop(0)
+ result = []
+ while True:
+ result.append(tokens.pop(0))
+ token = tokens.pop(0)
+ if isinstance(token, Repeat):
+ result += [result[-1]] * (token.count - 1)
+ token = tokens.pop(0)
+ if token == "}":
+ return result
+ assert token == ","
+
+def parse_dict_or_list(tokens):
+ assert tokens[0] == "{"
+ if tokens[2] == "=":
+ return parse_dict(tokens)
else:
- return int(text, 0)
+ return parse_list(tokens)
+
+def parse_tokens(tokens):
+ if isinstance(tokens[0], (float, int)):
+ return tokens.pop(0)
+ if tokens[0] == "{":
+ return parse_dict_or_list(tokens)
+ if isinstance(tokens[0], str):
+ return tokens.pop(0)
+ raise Exception("Unsupported tokens: %r" % tokens)
+
+def parse_rhs(text):
+ tokens = list(tokenize(text))
+ result = parse_tokens(tokens)
+ if tokens:
+ raise Exception("Unexpected input: %r" % tokens)
+ return result
class Gdb:
"""A single gdb class which can interact with one or more gdb instances."""
@@ -622,7 +701,7 @@ class Gdb:
output = self.command("info registers %s" % group, ops=5)
result = {}
for line in output.splitlines():
- m = re.match(r"(\w+)\s+({.*})\s+(\(.*\))", line)
+ m = re.match(r"(\w+)\s+({.*})(?:\s+(\(.*\)))?", line)
if m:
parts = m.groups()
else: