diff options
author | Tim Newsome <tim@sifive.com> | 2021-05-07 11:49:42 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-07 11:49:42 -0700 |
commit | c9f43c1652c1d8abf85f3466f41ffd5ec4d911d6 (patch) | |
tree | 21306f7c8d15ad937e2e234d564e81a0e43efa86 /debug/testlib.py | |
parent | 1b05661baa79f03830f5ddefa999dc7aaf7b1ce1 (diff) | |
download | riscv-tests-c9f43c1652c1d8abf85f3466f41ffd5ec4d911d6.zip riscv-tests-c9f43c1652c1d8abf85f3466f41ffd5ec4d911d6.tar.gz riscv-tests-c9f43c1652c1d8abf85f3466f41ffd5ec4d911d6.tar.bz2 |
Test daisy chained homogeneous spike instances. (#334)
* Test debugging multiple spikes in a daisy chain.
* Hugely speed up rbb_daisychain.
Now 2 dual-hart spikes are less than 4x slower than a single dual-hart
spike.
* WIP
* Test daisy chained homogeneous spike instances.
For OpenOCD, this means we're checking that we can talk to multiple
TAPs. Next up is heterogeneous testing.
* Enable Sv48Test.
Didn't mean to disable it with this commit.
* Test authentication again.
Another change I hadn't meant to push...
Diffstat (limited to 'debug/testlib.py')
-rw-r--r-- | debug/testlib.py | 121 |
1 files changed, 89 insertions, 32 deletions
diff --git a/debug/testlib.py b/debug/testlib.py index 501e0e6..cde6597 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -65,7 +65,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, vlen=128, elen=64, slen=128): + support_haltgroups=True, vlen=128, elen=64, slen=128, harts=None): """Launch spike. Return tuple of its process and the port it's running on.""" self.process = None @@ -80,21 +80,19 @@ class Spike: self.elen = elen self.slen = slen - if target.harts: - harts = target.harts - else: - harts = [target] + self.harts = harts or target.harts or [target] - cmd = self.command(target, harts, halted, timeout, with_jtag_gdb) - self.infinite_loop = target.compile(harts[0], + cmd = self.command(target, halted, timeout, with_jtag_gdb) + self.infinite_loop = target.compile(self.harts[0], "programs/checksum.c", "programs/tiny-malloc.c", "programs/infinite_loop.S", "-DDEFINE_MALLOC", "-DDEFINE_FREE") cmd.append(self.infinite_loop) self.logfile = tempfile.NamedTemporaryFile(prefix="spike-", suffix=".log") - self.logname = self.logfile.name + logname = self.logfile.name + self.lognames = [logname] if print_log_names: - real_stdout.write("Temporary spike log: %s\n" % self.logname) + real_stdout.write("Temporary spike log: %s\n" % logname) self.logfile.write(("+ %s\n" % " ".join(cmd)).encode()) self.logfile.flush() self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, @@ -104,34 +102,34 @@ class Spike: self.port = None for _ in range(30): m = re.search(r"Listening for remote bitbang connection on " - r"port (\d+).", open(self.logname).read()) + r"port (\d+).", open(logname).read()) if m: self.port = int(m.group(1)) os.environ['REMOTE_BITBANG_PORT'] = m.group(1) break time.sleep(0.11) if not self.port: - print_log(self.logname) + print_log(logname) raise Exception("Didn't get spike message about bitbang " "connection") # pylint: disable=too-many-branches - def command(self, target, harts, halted, timeout, with_jtag_gdb): + def command(self, target, halted, timeout, with_jtag_gdb): # pylint: disable=no-self-use if target.sim_cmd: cmd = shlex.split(target.sim_cmd) else: cmd = ["spike"] - cmd += ["-p%d" % len(harts)] + cmd += ["-p%d" % len(self.harts)] - assert len(set(t.xlen for t in harts)) == 1, \ + assert len(set(t.xlen for t in self.harts)) == 1, \ "All spike harts must have the same XLEN" if self.isa: isa = self.isa else: - isa = "RV%dG" % harts[0].xlen + isa = "RV%dG" % self.harts[0].xlen cmd += ["--isa", isa] cmd += ["--dm-auth"] @@ -159,12 +157,12 @@ class Spike: cmd.append("--varch=vlen:%d,elen:%d,slen:%d" % (self.vlen, self.elen, self.slen)) - assert len(set(t.ram for t in harts)) == 1, \ + assert len(set(t.ram for t in self.harts)) == 1, \ "All spike harts must have the same RAM layout" - assert len(set(t.ram_size for t in harts)) == 1, \ + assert len(set(t.ram_size for t in self.harts)) == 1, \ "All spike harts must have the same RAM layout" - os.environ['WORK_AREA'] = '0x%x' % harts[0].ram - cmd += ["-m0x%x:0x%x" % (harts[0].ram, harts[0].ram_size)] + os.environ['WORK_AREA'] = '0x%x' % self.harts[0].ram + cmd += ["-m0x%x:0x%x" % (self.harts[0].ram, self.harts[0].ram_size)] if timeout: cmd = ["timeout", str(timeout)] + cmd @@ -188,6 +186,48 @@ class Spike: def wait(self, *args, **kwargs): return self.process.wait(*args, **kwargs) +class MultiSpike: + def __init__(self, spikes): + self.process = None + + self.spikes = spikes + self.lognames = sum((spike.lognames for spike in spikes), []) + self.logfile = tempfile.NamedTemporaryFile(prefix="daisychain-", + suffix=".log") + self.lognames.append(self.logfile.name) + + # Now create the daisy-chain process. + cmd = ["./rbb_daisychain.py", "0"] + \ + [str(spike.port) for spike in spikes] + self.logfile.write(("+ %s\n" % cmd).encode()) + self.logfile.flush() + self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, + stdout=self.logfile, stderr=self.logfile) + + self.port = None + for _ in range(30): + m = re.search(r"Listening on port (\d+).", + open(self.lognames[-1]).read()) + if m: + self.port = int(m.group(1)) + break + time.sleep(0.11) + if not self.port: + print_log(self.lognames[-1]) + raise Exception("Didn't get daisy chain message about which port " + "it's listening on.") + + os.environ['REMOTE_BITBANG_HOST'] = 'localhost' + os.environ['REMOTE_BITBANG_PORT'] = str(self.port) + + def __del__(self): + if self.process: + try: + self.process.kill() + self.process.wait() + except OSError: + pass + class VcsSim: logfile = tempfile.NamedTemporaryFile(prefix='simv', suffix='.log') logname = logfile.name @@ -519,11 +559,12 @@ 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, ports, + def __init__(self, target, ports, cmd="riscv64-unknown-elf-gdb", timeout=60, binary=None): assert ports + self.target = target self.ports = ports self.cmd = cmd self.timeout = timeout @@ -551,14 +592,16 @@ class Gdb: for port, child in zip(self.ports, self.children): self.select_child(child) self.wait() - self.command("set style enabled off") - self.command("set confirm off") - self.command("set width 0") - self.command("set height 0") + self.command("set style enabled off", reset_delays=None) + self.command("set confirm off", reset_delays=None) + self.command("set width 0", reset_delays=None) + self.command("set height 0", reset_delays=None) # Force consistency. - self.command("set print entry-values no") - self.command("set remotetimeout %d" % self.timeout) - self.command("target extended-remote localhost:%d" % port, ops=10) + self.command("set print entry-values no", reset_delays=None) + self.command("set remotetimeout %d" % self.timeout, + 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) threads = self.threads() @@ -635,6 +678,20 @@ class Gdb: self.select_child(child) self.command(command) + def system_command(self, command, ops=20): + """Execute this command on every unique system that we control.""" + done = set() + output = "" + with PrivateState(self): + for i, child in enumerate(self.children): + self.select_child(child) + if self.target.harts[i].system in done: + self.command("set $pc=_start") + else: + output += self.command(command, ops=ops) + done.add(self.target.harts[i].system) + return output + def c(self, wait=True, sync=True, checkOutput=True, ops=20): """ Dumb c command. @@ -742,10 +799,10 @@ class Gdb: return output def load(self): - output = self.command("load", ops=1000) + output = self.system_command("load", ops=1000) assert "failed" not in output assert "Transfer rate" in output - output = self.command("compare-sections", ops=1000) + output = self.system_command("compare-sections", ops=1000) assert "matched" in output assert "MIS" not in output @@ -986,7 +1043,7 @@ class BaseTest: self.compile() self.target_process = self.target.create() if self.target_process: - self.logs.append(self.target_process.logname) + self.logs += self.target_process.lognames try: self.server = self.target.server(self) self.logs.append(self.server.logname) @@ -1076,10 +1133,10 @@ class GdbTest(BaseTest): BaseTest.classSetup(self) if gdb_cmd: - self.gdb = Gdb(self.server.gdb_ports, 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.server.gdb_ports, + self.gdb = Gdb(self.target, self.server.gdb_ports, timeout=self.target.timeout_sec, binary=self.binary) self.logs += self.gdb.lognames() |