Merge pull request #117 from riscv/multicore_debug
[riscv-isa-sim.git] / tests / testlib.py
1 import os.path
2 import pexpect
3 import subprocess
4 import tempfile
5 import testlib
6 import unittest
7
8 # Note that gdb comes with its own testsuite. I was unable to figure out how to
9 # run that testsuite against the spike simulator.
10
11 def find_file(path):
12 for directory in (os.getcwd(), os.path.dirname(testlib.__file__)):
13 fullpath = os.path.join(directory, path)
14 if os.path.exists(fullpath):
15 return fullpath
16 return None
17
18 def compile(*args):
19 """Compile a single .c file into a binary."""
20 dst = os.path.splitext(args[0])[0]
21 cc = os.path.expandvars("$RISCV/bin/riscv64-unknown-elf-gcc")
22 cmd = [cc, "-g", "-O", "-o", dst]
23 for arg in args:
24 found = find_file(arg)
25 if found:
26 cmd.append(found)
27 else:
28 cmd.append(arg)
29 cmd = " ".join(cmd)
30 result = os.system(cmd)
31 assert result == 0, "%r failed" % cmd
32 return dst
33
34 def unused_port():
35 # http://stackoverflow.com/questions/2838244/get-open-tcp-port-in-python/2838309#2838309
36 import socket
37 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
38 s.bind(("",0))
39 port = s.getsockname()[1]
40 s.close()
41 return port
42
43 class Spike(object):
44 def __init__(self, binary, halted=False, with_gdb=True, timeout=None):
45 """Launch spike. Return tuple of its process and the port it's running on."""
46 cmd = []
47 if timeout:
48 cmd += ["timeout", str(timeout)]
49
50 cmd += [find_file("spike")]
51 if halted:
52 cmd.append('-H')
53 if with_gdb:
54 self.port = unused_port()
55 cmd += ['--gdb-port', str(self.port)]
56 cmd.append('pk')
57 if binary:
58 cmd.append(binary)
59 logfile = open("spike.log", "w")
60 self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=logfile,
61 stderr=logfile)
62
63 def __del__(self):
64 try:
65 self.process.kill()
66 self.process.wait()
67 except OSError:
68 pass
69
70 def wait(self, *args, **kwargs):
71 return self.process.wait(*args, **kwargs)
72
73 class Gdb(object):
74 def __init__(self):
75 path = os.path.expandvars("$RISCV/bin/riscv64-unknown-elf-gdb")
76 self.child = pexpect.spawn(path)
77 self.child.logfile = file("gdb.log", "w")
78 self.wait()
79 self.command("set width 0")
80 self.command("set height 0")
81 # Force consistency.
82 self.command("set print entry-values no")
83
84 def wait(self):
85 """Wait for prompt."""
86 self.child.expect("\(gdb\)")
87
88 def command(self, command, timeout=-1):
89 self.child.sendline(command)
90 self.child.expect("\n", timeout=timeout)
91 self.child.expect("\(gdb\)", timeout=timeout)
92 return self.child.before.strip()
93
94 def c(self, wait=True):
95 if wait:
96 return self.command("c")
97 else:
98 self.child.sendline("c")
99 self.child.expect("Continuing")
100
101 def interrupt(self):
102 self.child.send("\003");
103 self.child.expect("\(gdb\)")
104
105 def x(self, address, size='w'):
106 output = self.command("x/%s %s" % (size, address))
107 value = int(output.split(':')[1].strip(), 0)
108 return value
109
110 def p(self, obj):
111 output = self.command("p %s" % obj)
112 value = int(output.split('=')[-1].strip())
113 return value
114
115 def stepi(self):
116 return self.command("stepi")