From 09cfdaacd9322cf0ac94818d8c852e1f4dc5bc4f Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 20 May 2021 11:52:21 -0700 Subject: Test multiple heterogeneous spike instances. (#338) --- debug/gdbserver.py | 28 +++++++++++++++------ debug/targets.py | 25 ++++++++++++------- debug/targets/RISC-V/spike-multi.py | 22 ++++++----------- debug/targets/RISC-V/spike32.py | 4 --- debug/targets/RISC-V/spike64.py | 5 +--- debug/testlib.py | 49 ++++++++++++++++++------------------- 6 files changed, 70 insertions(+), 63 deletions(-) diff --git a/debug/gdbserver.py b/debug/gdbserver.py index ea5bb22..d4b7078 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -87,6 +87,10 @@ class InfoTest(GdbTest): continue if re.search(r"Disabling abstract command writes to CSRs.", line): continue + if re.search( + r"keep_alive.. was not invoked in the \d+ ms timelimit.", + line): + continue k, v = line.strip().split() info[k] = v assertEqual(int(info.get("hart.xlen")), self.hart.xlen) @@ -184,7 +188,7 @@ class CustomRegisterTest(SimpleRegisterTest): return self.target.implements_custom_test def check_custom(self, magic): - regs = {k: v for k, v in self.gdb.info_registers("all").items() + regs = {k: v for k, v in self.gdb.info_registers("all", ops=20).items() if k.startswith("custom")} assertEqual(set(regs.keys()), set(("custom1", @@ -796,7 +800,8 @@ class MemorySampleTest(DebugTest): self.gdb.p("i=123") @staticmethod - def check_incrementing_samples(raw_samples, check_addr, tolerance=0x100000): + def check_incrementing_samples(raw_samples, check_addr, + tolerance=0x200000): first_timestamp = None end = None total_samples = 0 @@ -871,7 +876,7 @@ class MemorySampleMixed(MemorySampleTest): raw_samples = self.collect_samples() self.check_incrementing_samples(raw_samples, addr["j"], - tolerance=0x200000) + tolerance=0x400000) self.check_samples_equal(raw_samples, addr["i32"], 0xdeadbeef) self.check_samples_equal(raw_samples, addr["i64"], 0x1122334455667788) @@ -935,7 +940,7 @@ class Semihosting(GdbSingleHartTest): self.gdb.b("main:begin") self.gdb.c() - self.gdb.p('filename="%s"' % temp.name) + self.gdb.p('filename="%s"' % temp.name, ops=2) self.exit() contents = open(temp.name, "r").readlines() @@ -1431,6 +1436,8 @@ class WriteCsrs(RegsTest): assertEqual(123, self.gdb.p("$csr832")) class DownloadTest(GdbTest): + compile_args = ("programs/infinite_loop.S", ) + def setup(self): # pylint: disable=attribute-defined-outside-init length = min(2**18, max(2**10, self.hart.ram_size - 2048)) @@ -1463,9 +1470,16 @@ class DownloadTest(GdbTest): if self.crc < 0: self.crc += 2**32 - self.binary = self.target.compile(self.hart, self.download_c.name, - "programs/checksum.c") - self.gdb.global_command("file %s" % self.binary) + compiled = {} + for hart in self.target.harts: + key = hart.system + if key not in compiled: + compiled[key] = self.target.compile(hart, self.download_c.name, + "programs/checksum.c") + self.gdb.select_hart(hart) + self.gdb.command("file %s" % compiled.get(key)) + + self.gdb.select_hart(self.hart) def test(self): self.gdb.load() diff --git a/debug/targets.py b/debug/targets.py index be45c62..dd0175e 100644 --- a/debug/targets.py +++ b/debug/targets.py @@ -44,12 +44,19 @@ class Hart: # jumpers. reset_vectors = [] - def __init__(self, system=None): - """system is set to an identifier of the system this hart belongs to. - Harts within the same system are assumed to share memory, and to have - unique hartids within that system. So for most cases the default - value of None is fine.""" - self.system = system + # system is set to an identifier of the system this hart belongs to. Harts + # within the same system are assumed to share memory, and to have unique + # hartids within that system. So for most cases the default value of None + # is fine. + system = None + + def __init__(self, misa=None, system=None, link_script_path=None): + if misa: + self.misa = misa + if system: + self.system = system + if link_script_path: + self.link_script_path = link_script_path def extensionSupported(self, letter): # target.misa is set by testlib.ExamineTarget @@ -162,10 +169,10 @@ class Target: freertos=test.freertos()) def do_compile(self, hart, *sources): - binary_name = "%s_%s-%d" % ( + binary_name = "%s_%s-%x" % ( self.name, os.path.basename(os.path.splitext(sources[0])[0]), - hart.xlen) + hart.misa) if Target.isolate: self.temporary_binary = tempfile.NamedTemporaryFile( prefix=binary_name + "_") @@ -203,7 +210,7 @@ class Target: return binary_name def compile(self, hart, *sources): - while True: + for _ in range(2): try: return self.do_compile(hart, *sources) except testlib.CompileError as e: diff --git a/debug/targets/RISC-V/spike-multi.py b/debug/targets/RISC-V/spike-multi.py index 9e85a35..816677b 100644 --- a/debug/targets/RISC-V/spike-multi.py +++ b/debug/targets/RISC-V/spike-multi.py @@ -2,16 +2,14 @@ import targets import testlib import spike32 # pylint: disable=import-error -#import spike64 # pylint: disable=import-error +import spike64 # pylint: disable=import-error class multispike(targets.Target): harts = [ spike32.spike32_hart(misa=0x4034112d, system=0), spike32.spike32_hart(misa=0x4034112d, system=0), - spike32.spike32_hart(misa=0x4034112d, system=1), - spike32.spike32_hart(misa=0x4034112d, system=1)] - #spike64.spike64_hart(misa=0x8000000000341129), - #spike64.spike64_hart(misa=0x8000000000341129)] + spike64.spike64_hart(misa=0x8000000000341129, system=1), + spike64.spike64_hart(misa=0x8000000000341129, system=1)] openocd_config_path = "spike-multi.cfg" # Increased timeout because we use abstract_rti to artificially slow things # down. @@ -25,15 +23,11 @@ class multispike(targets.Target): # requires vlen==slen. return testlib.MultiSpike( [ -# testlib.Spike(self, isa="RV64IMAFDV", abstract_rti=30, -# support_hasel=False, support_abstract_csr=False, -# vlen=512, elen=64, slen=512, harts=self.harts[:2]), - testlib.Spike(self, isa="RV32IMAFDCV", dmi_rti=4, + testlib.Spike(self, isa="RV64IMAFDV", + support_hasel=False, support_abstract_csr=False, + vlen=512, elen=64, slen=512, harts=self.harts[2:]), + testlib.Spike(self, isa="RV32IMAFDCV", support_abstract_csr=True, support_haltgroups=False, # elen must be at least 64 because D is supported. - elen=64, harts=self.harts[2:]), - 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, harts=self.harts[2:]) + elen=64, harts=self.harts[:2]), ]) diff --git a/debug/targets/RISC-V/spike32.py b/debug/targets/RISC-V/spike32.py index 6256574..17d28fb 100644 --- a/debug/targets/RISC-V/spike32.py +++ b/debug/targets/RISC-V/spike32.py @@ -10,10 +10,6 @@ class spike32_hart(targets.Hart): reset_vectors = [0x1000] link_script_path = "spike32.lds" - def __init__(self, misa, system=0): - super().__init__(system=system) - self.misa = misa - class spike32(targets.Target): harts = [spike32_hart(misa=0x4034112d)] openocd_config_path = "spike-1.cfg" diff --git a/debug/targets/RISC-V/spike64.py b/debug/targets/RISC-V/spike64.py index 4313968..31088ff 100644 --- a/debug/targets/RISC-V/spike64.py +++ b/debug/targets/RISC-V/spike64.py @@ -9,10 +9,7 @@ class spike64_hart(targets.Hart): instruction_hardware_breakpoint_count = 4 reset_vectors = [0x1000] link_script_path = "spike64.lds" - - def __init__(self, misa=0x8000000000141125, system=0): - super().__init__(system=system) - self.misa = misa + misa = 0x8000000000141125 class spike64(targets.Target): harts = [spike64_hart()] diff --git a/debug/testlib.py b/debug/testlib.py index cde6597..107c2dc 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -559,16 +559,14 @@ class Gdb: 11, 149, 107, 163, 73, 47, 43, 173, 7, 109, 101, 103, 191, 2, 139, 97, 193, 157, 3, 29, 79, 113, 5, 89, 19, 37, 71, 179, 59, 137, 53) - def __init__(self, target, ports, - cmd="riscv64-unknown-elf-gdb", - timeout=60, binary=None): + def __init__(self, target, ports, cmd=None, timeout=60, binaries=None): assert ports self.target = target self.ports = ports - self.cmd = cmd + self.cmd = cmd or "riscv64-unknown-elf-gdb" self.timeout = timeout - self.binary = binary + self.binaries = binaries or [None] * len(ports) self.reset_delay_index = 0 self.stack = [] @@ -582,14 +580,15 @@ class Gdb: self.logfiles.append(logfile) if print_log_names: real_stdout.write("Temporary gdb log: %s\n" % logfile.name) - child = pexpect.spawn(cmd) + child = pexpect.spawn(self.cmd) child.logfile = logfile - child.logfile.write(("+ %s\n" % cmd).encode()) + child.logfile.write(("+ %s\n" % self.cmd).encode()) self.children.append(child) self.active_child = self.children[0] def connect(self): - for port, child in zip(self.ports, self.children): + for port, child, binary in zip(self.ports, self.children, + self.binaries): self.select_child(child) self.wait() self.command("set style enabled off", reset_delays=None) @@ -602,8 +601,9 @@ class Gdb: reset_delays=None) self.command("target extended-remote localhost:%d" % port, ops=10, reset_delays=None) - if self.binary: - self.command("file %s" % self.binary) + if binary: + output = self.command("file %s" % binary) + assertIn("Reading symbols", output) threads = self.threads() for t in threads: hartid = None @@ -778,8 +778,8 @@ class Gdb: value = shlex.split(output.split('=')[-1].strip())[1] return value - def info_registers(self, group=""): - output = self.command("info registers %s" % group, ops=5) + def info_registers(self, group="", ops=5): + output = self.command("info registers %s" % group, ops=ops) result = {} for line in output.splitlines(): m = re.match(r"(\w+)\s+({.*})(?:\s+(\(.*\)))?", line) @@ -846,8 +846,6 @@ class Gdb: if m: threads.append(Thread(*m.groups())) assert threads - #>>>if not threads: - #>>> threads.append(Thread('1', '1', 'Default', '???')) return threads def thread(self, thread): @@ -1002,6 +1000,7 @@ def print_log(path): print_log_handle(path, open(path, "r")) class BaseTest: + # pylint: disable=too-many-instance-attributes compiled = {} def __init__(self, target, hart=None): @@ -1015,6 +1014,7 @@ class BaseTest: self.binary = None self.start = 0 self.logs = [] + self.binaries = [] def early_applicable(self): """Return a false value if the test has determined it cannot run @@ -1033,11 +1033,14 @@ class BaseTest: def compile(self): compile_args = getattr(self, 'compile_args', None) + self.binaries = [] if compile_args: - if compile_args not in BaseTest.compiled: - BaseTest.compiled[compile_args] = \ - self.target.compile(self.hart, *compile_args) - self.binary = BaseTest.compiled.get(compile_args) + for hart in self.target.harts: + key = (compile_args, hart.misa) + if key not in BaseTest.compiled: + BaseTest.compiled[key] = \ + self.target.compile(hart, *compile_args) + self.binaries.append(BaseTest.compiled.get(key)) def classSetup(self): self.compile() @@ -1061,7 +1064,7 @@ class BaseTest: def run(self): """ - If compile_args is set, compile a program and set self.binary. + If compile_args is set, compile a program and set self.binaries. Call setup(). @@ -1132,12 +1135,8 @@ class GdbTest(BaseTest): def classSetup(self): BaseTest.classSetup(self) - if gdb_cmd: - self.gdb = Gdb(self.target, self.server.gdb_ports, gdb_cmd, - timeout=self.target.timeout_sec, binary=self.binary) - else: - self.gdb = Gdb(self.target, self.server.gdb_ports, - timeout=self.target.timeout_sec, binary=self.binary) + self.gdb = Gdb(self.target, self.server.gdb_ports, cmd=gdb_cmd, + timeout=self.target.timeout_sec, binaries=self.binaries) self.logs += self.gdb.lognames() self.gdb.connect() -- cgit v1.1