aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdebug/gdbserver.py59
-rwxr-xr-xdebug/openocd.py2
-rw-r--r--debug/programs/step.S8
-rw-r--r--debug/programs/trigger.S1
-rw-r--r--debug/targets.py7
-rw-r--r--debug/testlib.py93
6 files changed, 109 insertions, 61 deletions
diff --git a/debug/gdbserver.py b/debug/gdbserver.py
index 323d32c..9dfea39 100755
--- a/debug/gdbserver.py
+++ b/debug/gdbserver.py
@@ -11,6 +11,7 @@ import targets
import testlib
from testlib import assertEqual, assertNotEqual, assertIn
from testlib import assertGreater, assertTrue, assertRegexpMatches, assertLess
+from testlib import GdbTest
MSTATUS_UIE = 0x00000001
MSTATUS_SIE = 0x00000002
@@ -34,30 +35,6 @@ MSTATUS64_SD = 0x8000000000000000
# pylint: disable=abstract-method
-def gdb(
- target=None,
- port=None,
- binary=None
- ):
-
- g = None
- if parsed.gdb:
- g = testlib.Gdb(parsed.gdb)
- else:
- g = testlib.Gdb()
-
- if binary:
- g.command("file %s" % binary)
- if target:
- g.command("set arch riscv:rv%d" % target.xlen)
- g.command("set remotetimeout %d" % target.timeout_sec)
- if port:
- g.command("target extended-remote localhost:%d" % port)
-
- g.p("$priv=3")
-
- return g
-
def ihex_line(address, record_type, data):
assert len(data) < 128
line = ":%02X%04X%02X" % (len(data), address, record_type)
@@ -86,20 +63,6 @@ def ihex_parse(line):
def readable_binary_string(s):
return "".join("%02x" % ord(c) for c in s)
-class GdbTest(testlib.BaseTest):
- def __init__(self, target):
- testlib.BaseTest.__init__(self, target)
- self.gdb = None
-
- def classSetup(self):
- testlib.BaseTest.classSetup(self)
- self.logs.append("gdb.log")
- self.gdb = gdb(self.target, self.server.port, self.binary)
-
- def classTeardown(self):
- del self.gdb
- testlib.BaseTest.classTeardown(self)
-
class SimpleRegisterTest(GdbTest):
def check_reg(self, name):
a = random.randrange(1<<self.target.xlen)
@@ -145,10 +108,10 @@ class SimpleF18Test(SimpleRegisterTest):
self.gdb.stepi()
assertLess(abs(float(self.gdb.p_raw("$%s" % name)) - b), .001)
+ def early_applicable(self):
+ return self.target.extensionSupported('F')
+
def test(self):
- misa = self.gdb.p("$misa")
- if not misa & (1<<(ord('F')-ord('A'))):
- return 'not_applicable'
self.check_reg("f18")
class SimpleMemoryTest(GdbTest):
@@ -440,10 +403,14 @@ class StepTest(GdbTest):
def test(self):
main_address = self.gdb.p("$pc")
- for expected in (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c):
+ if self.target.extensionSupported("c"):
+ sequence = (4, 8, 0xc, 0xe, 0x14, 0x18, 0x22, 0x1c, 0x24, 0x24)
+ else:
+ sequence = (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c)
+ for expected in sequence:
self.gdb.stepi()
pc = self.gdb.p("$pc")
- assertEqual("%x" % pc, "%x" % (expected + main_address))
+ assertEqual("%x" % (pc - main_address), "%x" % expected)
class TriggerTest(GdbTest):
compile_args = ("programs/trigger.S", )
@@ -656,7 +623,7 @@ class PrivTest(GdbTest):
# pylint: disable=attribute-defined-outside-init
self.gdb.load()
- misa = self.gdb.p("$misa")
+ misa = self.target.misa
self.supported = set()
if misa & (1<<20):
self.supported.add(0)
@@ -710,8 +677,6 @@ def main():
./gdbserver.py --freedom-e300 --cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" Simple
""")
targets.add_target_options(parser)
- parser.add_argument("--gdb",
- help="The command to use to start gdb.")
testlib.add_test_run_options(parser)
@@ -725,7 +690,7 @@ def main():
module = sys.modules[__name__]
- return testlib.run_all_tests(module, target, parsed.test, parsed.fail_fast)
+ return testlib.run_all_tests(module, target, parsed)
# TROUBLESHOOTING TIPS
# If a particular test fails, run just that one test, eg.:
diff --git a/debug/openocd.py b/debug/openocd.py
index 0ab8810..50c6f3c 100755
--- a/debug/openocd.py
+++ b/debug/openocd.py
@@ -79,7 +79,7 @@ def main():
module = sys.modules[__name__]
- return testlib.run_all_tests(module, target, parsed.test, parsed.fail_fast)
+ return testlib.run_all_tests(module, target, parsed)
if __name__ == '__main__':
sys.exit(main())
diff --git a/debug/programs/step.S b/debug/programs/step.S
index 6601548..3e7b42e 100644
--- a/debug/programs/step.S
+++ b/debug/programs/step.S
@@ -11,14 +11,18 @@ main:
nop // 0x14
one:
beq zero, t0, one // 0x18
- jal two // 0x1c
+ // Use t0 instead of ra to force a 32-bit opcode in C mode. Otherwise
+ // 32-bit and 64-bit binaries end up with different instructions (I
+ // didn't pursue this).
+ jal t0, two // 0x1c
three:
.word 0 // 0x20
nop // 0x24
two:
- ret // 0x28
+ jr t0 // 0x28
+ .align 2
trap_entry:
j trap_entry // 0x2c
diff --git a/debug/programs/trigger.S b/debug/programs/trigger.S
index d87b71e..ac5a2f8 100644
--- a/debug/programs/trigger.S
+++ b/debug/programs/trigger.S
@@ -101,6 +101,7 @@ read_triggers:
ret
.data
+ .align 3
data: .word 0x40
.word 0x41
.word 0x42
diff --git a/debug/targets.py b/debug/targets.py
index c431a67..bcebc0b 100644
--- a/debug/targets.py
+++ b/debug/targets.py
@@ -12,6 +12,7 @@ class Target(object):
temporary_binary = None
openocd_config = []
use_fpu = False
+ misa = None
def __init__(self, cmd, run, isolate):
self.cmd = cmd
@@ -42,6 +43,8 @@ class Target(object):
march = "rv%dima" % self.xlen
if self.use_fpu:
march += "fd"
+ if self.extensionSupported("c"):
+ march += "c"
testlib.compile(sources +
("programs/entry.S", "programs/init.c",
"-I", "../env",
@@ -54,6 +57,10 @@ class Target(object):
xlen=self.xlen)
return binary_name
+ def extensionSupported(self, letter):
+ # target.misa is set by testlib.ExamineTarget
+ return self.misa & (1 << (ord(letter.upper()) - ord('A')))
+
class SpikeTarget(Target):
# pylint: disable=abstract-method
directory = "spike"
diff --git a/debug/testlib.py b/debug/testlib.py
index ac1d771..a762174 100644
--- a/debug/testlib.py
+++ b/debug/testlib.py
@@ -327,23 +327,31 @@ class Gdb(object):
assert "Hardware assisted breakpoint" in output
return output
-def run_all_tests(module, target, tests, fail_fast):
+def run_all_tests(module, target, parsed):
good_results = set(('pass', 'not_applicable'))
start = time.time()
results = {}
count = 0
+
+ global gdb_cmd # pylint: disable=global-statement
+ gdb_cmd = parsed.gdb
+
+ todo = [("ExamineTarget", ExamineTarget)]
for name in dir(module):
definition = getattr(module, name)
if type(definition) == type and hasattr(definition, 'test') and \
- (not tests or any(test in name for test in tests)):
- instance = definition(target)
- result = instance.run()
- results.setdefault(result, []).append(name)
- count += 1
- if result not in good_results and fail_fast:
- break
+ (not parsed.test or any(test in name for test in parsed.test)):
+ todo.append((name, definition))
+
+ for name, definition in todo:
+ instance = definition(target)
+ result = instance.run()
+ results.setdefault(result, []).append(name)
+ count += 1
+ if result not in good_results and parsed.fail_fast:
+ break
header("ran %d tests in %.0fs" % (count, time.time() - start), dash=':')
@@ -362,6 +370,8 @@ def add_test_run_options(parser):
help="Exit as soon as any test fails.")
parser.add_argument("test", nargs='*',
help="Run only tests that are named here.")
+ parser.add_argument("--gdb",
+ help="The command to use to start gdb.")
def header(title, dash='-'):
if title:
@@ -372,9 +382,21 @@ def header(title, dash='-'):
else:
print dash * 40
+def print_log(path):
+ header(path)
+ lines = open(path, "r").readlines()
+ if len(lines) > 1000:
+ for l in lines[:500]:
+ sys.stdout.write(l)
+ print "..."
+ for l in lines[-500:]:
+ sys.stdout.write(l)
+ else:
+ for l in lines:
+ sys.stdout.write(l)
+
class BaseTest(object):
compiled = {}
- logs = []
def __init__(self, target):
self.target = target
@@ -382,6 +404,7 @@ class BaseTest(object):
self.target_process = None
self.binary = None
self.start = 0
+ self.logs = []
def early_applicable(self):
"""Return a false value if the test has determined it cannot run
@@ -450,8 +473,7 @@ class BaseTest(object):
header("Traceback")
traceback.print_exc(file=sys.stdout)
for log in self.logs:
- header(log)
- print open(log, "r").read()
+ print_log(log)
print "/" * 40
return result
@@ -463,6 +485,55 @@ class BaseTest(object):
print "%s in %.2fs" % (result, time.time() - self.start)
return result
+gdb_cmd = None
+class GdbTest(BaseTest):
+ def __init__(self, target):
+ BaseTest.__init__(self, target)
+ self.gdb = None
+
+ def classSetup(self):
+ BaseTest.classSetup(self)
+ self.logs.append("gdb.log")
+
+ if gdb_cmd:
+ self.gdb = Gdb(gdb_cmd)
+ else:
+ self.gdb = Gdb()
+
+ if self.binary:
+ self.gdb.command("file %s" % self.binary)
+ if self.target:
+ self.gdb.command("set arch riscv:rv%d" % self.target.xlen)
+ self.gdb.command("set remotetimeout %d" % self.target.timeout_sec)
+ if self.server.port:
+ self.gdb.command(
+ "target extended-remote localhost:%d" % self.server.port)
+
+ self.gdb.p("$priv=3")
+
+ def classTeardown(self):
+ del self.gdb
+ BaseTest.classTeardown(self)
+
+class ExamineTarget(GdbTest):
+ def test(self):
+ self.target.misa = self.gdb.p("$misa")
+
+ txt = "RV"
+ if (self.target.misa >> 30) == 1:
+ txt += "32"
+ elif (self.target.misa >> 62) == 2:
+ txt += "64"
+ elif (self.target.misa >> 126) == 3:
+ txt += "128"
+ else:
+ txt += "??"
+
+ for i in range(26):
+ if self.target.misa & (1<<i):
+ txt += chr(i + ord('A'))
+ print txt,
+
class TestFailed(Exception):
def __init__(self, message):
Exception.__init__(self)