X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=debug%2Ftestlib.py;h=29fa1703efdd81f339e726a649e700bac4d77bf1;hb=c5e29cf553799b0434e2635e3f42314af337a5b2;hp=c186a175a5cc9d50a8c26d7c49618fa474dd6e2f;hpb=5ad886f909376920d345c7cf1f7b70c7ef37392f;p=riscv-tests.git diff --git a/debug/testlib.py b/debug/testlib.py index c186a17..29fa170 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -1,8 +1,7 @@ import os.path +import re import shlex import subprocess -import tempfile -import unittest import time import pexpect @@ -17,7 +16,7 @@ def find_file(path): return fullpath return None -def compile(args, xlen=32): +def compile(args, xlen=32): # pylint: disable=redefined-builtin cc = os.path.expandvars("$RISCV/bin/riscv%d-unknown-elf-gcc" % xlen) cmd = [cc, "-g"] for arg in args: @@ -34,20 +33,23 @@ def unused_port(): # http://stackoverflow.com/questions/2838244/get-open-tcp-port-in-python/2838309#2838309 import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.bind(("",0)) + s.bind(("", 0)) port = s.getsockname()[1] s.close() return port class Spike(object): - def __init__(self, cmd, binary=None, halted=False, with_gdb=True, timeout=None, - xlen=64): - """Launch spike. Return tuple of its process and the port it's running on.""" + logname = "spike.log" + + def __init__(self, cmd, binary=None, halted=False, with_gdb=True, + timeout=None, xlen=64): + """Launch spike. Return tuple of its process and the port it's running + on.""" if cmd: cmd = shlex.split(cmd) else: cmd = ["spike"] - if (xlen == 32): + if xlen == 32: cmd += ["--isa", "RV32"] if timeout: @@ -58,14 +60,15 @@ class Spike(object): if with_gdb: self.port = unused_port() cmd += ['--gdb-port', str(self.port)] + cmd.append("-m32") cmd.append('pk') if binary: cmd.append(binary) - logfile = open("spike.log", "w") + logfile = open(self.logname, "w") logfile.write("+ %s\n" % " ".join(cmd)) logfile.flush() - self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=logfile, - stderr=logfile) + self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, + stdout=logfile, stderr=logfile) def __del__(self): try: @@ -82,7 +85,7 @@ class VcsSim(object): if simv: cmd = shlex.split(simv) else: - cmd = ["simv"] + cmd = ["simv"] cmd += ["+jtag_vpi_enable"] if debug: cmd[0] = cmd[0] + "-debug" @@ -91,17 +94,17 @@ class VcsSim(object): logfile.write("+ %s\n" % " ".join(cmd)) logfile.flush() listenfile = open("simv.log", "r") - listenfile.seek(0,2) - self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=logfile, - stderr=logfile) + listenfile.seek(0, 2) + self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, + stdout=logfile, stderr=logfile) done = False - while (not done): + while not done: line = listenfile.readline() - if (not line): + if not line: time.sleep(1) - if ("Listening on port 5555" in line): + if "Listening on port 5555" in line: done = True - + def __del__(self): try: self.process.kill() @@ -109,8 +112,9 @@ class VcsSim(object): except OSError: pass - class Openocd(object): + logname = "openocd.log" + def __init__(self, cmd=None, config=None, debug=False, otherProcess=None): # keep handles to other processes -- don't let them be @@ -125,12 +129,34 @@ class Openocd(object): cmd += ["-f", find_file(config)] if debug: cmd.append("-d") - logfile = open("openocd.log", "w") + + # Assign port + self.port = unused_port() + print "Using port %d for gdb server" % self.port + # This command needs to come before any config scripts on the command + # line, since they are executed in order. + cmd[1:1] = ["--command", "gdb_port %d" % self.port] + + logfile = open(Openocd.logname, "w") logfile.write("+ %s\n" % " ".join(cmd)) - self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=logfile, - stderr=logfile) - # TODO: Pick a random port - self.port = 3333 + logfile.flush() + self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, + stdout=logfile, stderr=logfile) + + # Wait for OpenOCD to have made it through riscv_examine(). When using + # OpenOCD to communicate with a simulator this may take a long time, + # and gdb will time out when trying to connect if we attempt too early. + start = time.time() + messaged = False + while True: + log = open(Openocd.logname).read() + if "Examined RISCV core" in log: + break + if not self.process.poll() is None: + raise Exception("OpenOCD exited before completing riscv_examine()") + if not messaged and time.time() - start > 1: + messaged = True + print "Waiting for OpenOCD to examine RISCV core..." def __del__(self): try: @@ -139,11 +165,16 @@ class Openocd(object): except OSError: pass +class CannotAccess(Exception): + def __init__(self, address): + Exception.__init__(self) + self.address = address + class Gdb(object): def __init__(self, cmd=os.path.expandvars("$RISCV/bin/riscv64-unknown-elf-gdb")): self.child = pexpect.spawn(cmd) - self.child.logfile = file("gdb.log", "w") + self.child.logfile = open("gdb.log", "w") self.child.logfile.write("+ %s\n" % cmd) self.wait() self.command("set confirm off") @@ -154,12 +185,12 @@ class Gdb(object): def wait(self): """Wait for prompt.""" - self.child.expect("\(gdb\)") + self.child.expect(r"\(gdb\)") def command(self, command, timeout=-1): self.child.sendline(command) self.child.expect("\n", timeout=timeout) - self.child.expect("\(gdb\)", timeout=timeout) + self.child.expect(r"\(gdb\)", timeout=timeout) return self.child.before.strip() def c(self, wait=True): @@ -172,8 +203,8 @@ class Gdb(object): self.child.expect("Continuing") def interrupt(self): - self.child.send("\003"); - self.child.expect("\(gdb\)") + self.child.send("\003") + self.child.expect(r"\(gdb\)", timeout=60) return self.child.before.strip() def x(self, address, size='w'): @@ -183,12 +214,19 @@ class Gdb(object): def p(self, obj): output = self.command("p/x %s" % obj) + m = re.search("Cannot access memory at address (0x[0-9a-f]+)", output) + if m: + raise CannotAccess(int(m.group(1), 0)) value = int(output.split('=')[-1].strip(), 0) return value + def p_string(self, obj): + output = self.command("p %s" % obj) + value = shlex.split(output.split('=')[-1].strip())[1] + return value + def stepi(self): output = self.command("stepi") - assert "Cannot" not in output return output def load(self):