diff options
-rwxr-xr-x | debug/gdbserver.py | 59 | ||||
-rwxr-xr-x | debug/openocd.py | 2 | ||||
-rw-r--r-- | debug/programs/step.S | 8 | ||||
-rw-r--r-- | debug/programs/trigger.S | 1 | ||||
-rw-r--r-- | debug/targets.py | 7 | ||||
-rw-r--r-- | debug/testlib.py | 93 |
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) |