aboutsummaryrefslogtreecommitdiff
path: root/tests/testlib.py
blob: 4e05616390c83e47d43e7b22f461d77c0063e60b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import os.path
import pexpect
import subprocess
import tempfile
import testlib
import unittest

# Note that gdb comes with its own testsuite. I was unable to figure out how to
# run that testsuite against the spike simulator.

def find_file(path):
    for directory in (os.getcwd(), os.path.dirname(testlib.__file__)):
        fullpath = os.path.join(directory, path)
        if os.path.exists(fullpath):
            return fullpath
    raise ValueError("Couldn't find %r." % path)

def compile(src):
    """Compile a single .c file into a binary."""
    src = find_file(src)
    dst = os.path.splitext(src)[0]
    cc = os.path.expandvars("$RISCV/bin/riscv64-unknown-elf-gcc")
    cmd = "%s -g -o %s %s" % (cc, dst, src)
    result = os.system(cmd)
    assert result == 0, "%r failed" % cmd
    return dst

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))
    port = s.getsockname()[1]
    s.close()
    return port

def spike(binary, halted=False, with_gdb=True, timeout=None):
    """Launch spike. Return tuple of its process and the port it's running on."""
    cmd = []
    if timeout:
        cmd += ["timeout", str(timeout)]

    cmd += [find_file("spike")]
    if halted:
        cmd.append('-H')
    if with_gdb:
        port = unused_port()
        cmd += ['--gdb-port', str(port)]
    cmd += ['pk', binary]
    logfile = open("spike.log", "w")
    process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=logfile,
            stderr=logfile)
    if with_gdb:
        return process, port
    else:
        return process

class Gdb(object):
    def __init__(self):
        path = os.path.expandvars("$RISCV/bin/riscv64-unknown-elf-gdb")
        self.child = pexpect.spawn(path)
        self.child.logfile = file("gdb.log", "w")
        self.wait()
        self.command("set width 0")
        self.command("set height 0")

    def wait(self):
        """Wait for prompt."""
        self.child.expect("\(gdb\)")

    def command(self, command):
        self.child.sendline(command)
        self.child.expect("\n")
        self.child.expect("\(gdb\)")
        return self.child.before.strip()

    def x(self, address, size='w'):
        output = self.command("x/%s %s" % (size, address))
        value = int(output.split(':')[1].strip(), 0)
        return value

    def p(self, obj):
        output = self.command("p %s" % obj)
        value = int(output.split('=')[-1].strip())
        return value

    def stepi(self):
        return self.command("stepi")