X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=debug%2Fgdbserver.py;h=263dbd6e82bc5542d0ba724397af43c15cd5182f;hb=b83c1a818f1abbf893d2742f6718c2a72b36f59a;hp=1d5c60eb867e79751ea9dd1df6dd4c81464c55e5;hpb=bd1caacb3d912c51dfe428b99719f9454c744941;p=riscv-tests.git diff --git a/debug/gdbserver.py b/debug/gdbserver.py index 1d5c60e..263dbd6 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -10,6 +10,7 @@ import time import random import binascii + MSTATUS_UIE = 0x00000001 MSTATUS_SIE = 0x00000002 MSTATUS_HIE = 0x00000004 @@ -30,6 +31,29 @@ MSTATUS_VM = 0x1F000000 MSTATUS32_SD = 0x80000000 MSTATUS64_SD = 0x8000000000000000 +def gdb( + target=None, + port=None, + binary=None + ): + + gdb = None + if parsed.gdb: + gdb = testlib.Gdb(parsed.gdb) + else: + gdb = testlib.Gdb() + + if binary: + gdb.command("file %s" % binary) + if target: + gdb.command("set arch riscv:rv%d" % target.xlen) + gdb.command("set remotetimeout %d" % target.timeout_sec) + if port: + gdb.command("target extended-remote localhost:%d" % port) + + return gdb + + def ihex_line(address, record_type, data): assert len(data) < 128 line = ":%02X%04X%02X" % (len(data), address, record_type) @@ -55,6 +79,9 @@ def ihex_parse(line): data += "%c" % int(line[8+2*i:10+2*i], 16) return record_type, address, data +def readable_binary_string(s): + return "".join("%02x" % ord(c) for c in s) + class DeleteServer(unittest.TestCase): def tearDown(self): del self.server @@ -62,12 +89,7 @@ class DeleteServer(unittest.TestCase): class SimpleRegisterTest(DeleteServer): def setUp(self): self.server = target.server() - self.gdb = testlib.Gdb() - # For now gdb has to be told what the architecture is when it's not - # given an ELF file. - self.gdb.command("set arch riscv:rv%d" % target.xlen) - - self.gdb.command("target extended-remote localhost:%d" % self.server.port) + self.gdb = gdb(target, self.server.port) # 0x13 is nop self.gdb.command("p *((int*) 0x%x)=0x13" % target.ram) @@ -104,9 +126,7 @@ class SimpleRegisterTest(DeleteServer): class SimpleMemoryTest(DeleteServer): def setUp(self): self.server = target.server() - self.gdb = testlib.Gdb() - self.gdb.command("set arch riscv:rv%d" % target.xlen) - self.gdb.command("target extended-remote localhost:%d" % self.server.port) + self.gdb = gdb(target, self.server.port) def access_test(self, size, data_type): self.assertEqual(self.gdb.p("sizeof(%s)" % data_type), @@ -156,15 +176,14 @@ class SimpleMemoryTest(DeleteServer): for line in b: record_type, address, line_data = ihex_parse(line) if (record_type == 0): - self.assertEqual(line_data, data[address:address+len(line_data)]) + self.assertEqual(readable_binary_string(line_data), + readable_binary_string(data[address:address+len(line_data)])) class InstantHaltTest(DeleteServer): def setUp(self): self.server = target.server() - self.gdb = testlib.Gdb() - self.gdb.command("set arch riscv:rv%d" % target.xlen) - self.gdb.command("target extended-remote localhost:%d" % self.server.port) - + self.gdb = gdb(target, self.server.port) + def test_instant_halt(self): self.assertEqual(target.reset_vector, self.gdb.p("$pc")) # mcycle and minstret have no defined reset value. @@ -192,9 +211,7 @@ class DebugTest(DeleteServer): self.binary = target.compile("programs/debug.c", "programs/checksum.c", "programs/tiny-malloc.c", "-DDEFINE_MALLOC", "-DDEFINE_FREE") self.server = target.server() - self.gdb = testlib.Gdb() - self.gdb.command("file %s" % self.binary) - self.gdb.command("target extended-remote localhost:%d" % self.server.port) + self.gdb = gdb(target, self.server.port, self.binary) self.gdb.load() self.gdb.b("_exit") @@ -345,9 +362,7 @@ class StepTest(DeleteServer): def setUp(self): self.binary = target.compile("programs/step.S") self.server = target.server() - self.gdb = testlib.Gdb() - self.gdb.command("file %s" % self.binary) - self.gdb.command("target extended-remote localhost:%d" % self.server.port) + self.gdb = gdb(target, self.server.port, self.binary) self.gdb.load() self.gdb.b("main") self.gdb.c() @@ -363,9 +378,7 @@ class RegsTest(DeleteServer): def setUp(self): self.binary = target.compile("programs/regs.S") self.server = target.server() - self.gdb = testlib.Gdb() - self.gdb.command("file %s" % self.binary) - self.gdb.command("target extended-remote localhost:%d" % self.server.port) + self.gdb = gdb(target, self.server.port, self.binary) self.gdb.load() self.gdb.b("main") self.gdb.b("handle_trap") @@ -433,10 +446,8 @@ class DownloadTest(DeleteServer): self.binary = target.compile(download_c.name, "programs/checksum.c") self.server = target.server() - self.gdb = testlib.Gdb() - self.gdb.command("file %s" % self.binary) - self.gdb.command("target extended-remote localhost:%d" % self.server.port) - + self.gdb = gdb(target, self.server.port, self.binary) + def test_download(self): output = self.gdb.load() self.gdb.command("b _exit") @@ -447,9 +458,7 @@ class MprvTest(DeleteServer): def setUp(self): self.binary = target.compile("programs/mprv.S") self.server = target.server() - self.gdb = testlib.Gdb() - self.gdb.command("file %s" % self.binary) - self.gdb.command("target extended-remote localhost:%d" % self.server.port) + self.gdb = gdb(target, self.server.port, self.binary) self.gdb.load() def test_mprv(self): @@ -460,9 +469,60 @@ class MprvTest(DeleteServer): output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)") self.assertIn("0xbead", output) +class PrivTest(DeleteServer): + def setUp(self): + self.binary = target.compile("programs/priv.S") + self.server = target.server() + self.gdb = gdb(target, self.server.port, self.binary) + self.gdb.load() + + misa = self.gdb.p("$misa") + self.supported = set() + if misa & (1<<20): + self.supported.add(0) + if misa & (1<<18): + self.supported.add(1) + if misa & (1<<7): + self.supported.add(2) + self.supported.add(3) + + def test_rw(self): + """Test reading/writing priv.""" + for privilege in range(4): + self.gdb.p("$priv=%d" % privilege) + self.gdb.stepi() + actual = self.gdb.p("$priv") + self.assertIn(actual, self.supported) + if privilege in self.supported: + self.assertEqual(actual, privilege) + + def test_change(self): + """Test that the core's privilege level actually changes.""" + + if 0 not in self.supported: + # TODO: return not applicable + return + + self.gdb.b("main") + self.gdb.c() + + # Machine mode + self.gdb.p("$priv=3") + main = self.gdb.p("$pc") + self.gdb.stepi() + self.assertEqual("%x" % self.gdb.p("$pc"), "%x" % (main+4)) + + # User mode + self.gdb.p("$priv=0") + self.gdb.stepi() + # Should have taken an exception, so be nowhere near main. + pc = self.gdb.p("$pc") + self.assertTrue(pc < main or pc > main + 0x100) + class Target(object): directory = None - + timeout_sec = 2 + def server(self): raise NotImplementedError @@ -505,9 +565,36 @@ class Spike32Target(SpikeTarget): def server(self): return testlib.Spike(parsed.cmd, halted=True, xlen=32) -class MicroSemiTarget(Target): - name = "m2gl_m2s" +class FreedomE300Target(Target): + name = "freedom-e300" + xlen = 32 + ram = 0x80000000 + ram_size = 16 * 1024 + instruction_hardware_breakpoint_count = 2 + + def server(self): + return testlib.Openocd(cmd=parsed.cmd, + config="targets/%s/openocd.cfg" % self.name) + +class FreedomE300SimTarget(Target): + name = "freedom-e300-sim" xlen = 32 + timeout_sec = 240 + ram = 0x80000000 + ram_size = 256 * 1024 * 1024 + instruction_hardware_breakpoint_count = 2 + + def server(self): + sim = testlib.VcsSim(simv=parsed.run, debug=False) + openocd = testlib.Openocd(cmd=parsed.cmd, + config="targets/%s/openocd.cfg" % self.name, + otherProcess = sim) + time.sleep(20) + return openocd + +class FreedomU500Target(Target): + name = "freedom-u500" + xlen = 64 ram = 0x80000000 ram_size = 16 * 1024 instruction_hardware_breakpoint_count = 2 @@ -515,26 +602,48 @@ class MicroSemiTarget(Target): def server(self): return testlib.Openocd(cmd=parsed.cmd, config="targets/%s/openocd.cfg" % self.name) + +class FreedomU500SimTarget(Target): + name = "freedom-u500-sim" + xlen = 64 + timeout_sec = 240 + ram = 0x80000000 + ram_size = 256 * 1024 * 1024 + instruction_hardware_breakpoint_count = 2 + + def server(self): + sim = testlib.VcsSim(simv=parsed.run, debug=False) + openocd = testlib.Openocd(cmd=parsed.cmd, + config="targets/%s/openocd.cfg" % self.name, + otherProcess = sim) + time.sleep(20) + return openocd targets = [ Spike32Target, Spike64Target, - MicroSemiTarget - ] + FreedomE300Target, + FreedomU500Target, + FreedomE300SimTarget, + FreedomU500SimTarget] def main(): parser = argparse.ArgumentParser( epilog=""" Example command line from the real world: - Run all RegsTest cases against a MicroSemi m2gl_m2s board, with custom openocd command: - ./gdbserver.py --m2gl_m2s --cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" -- -vf RegsTest + Run all RegsTest cases against a physical FPGA, with custom openocd command: + ./gdbserver.py --freedom-e-300 --cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" -- -vf RegsTest """) group = parser.add_mutually_exclusive_group(required=True) for t in targets: group.add_argument("--%s" % t.name, action="store_const", const=t, dest="target") + parser.add_argument("--run", + help="The command to use to start the actual target (e.g. simulation)") parser.add_argument("--cmd", help="The command to use to start the debug server.") + parser.add_argument("--gdb", + help="The command to use to start gdb.") parser.add_argument("--isolate", action="store_true", help="Try to run in such a way that multiple instances can run at " "the same time. This may make it harder to debug a failure if it " @@ -549,7 +658,7 @@ def main(): # TROUBLESHOOTING TIPS # If a particular test fails, run just that one test, eg.: -# ./tests/gdbserver.py MprvTest.test_mprv +# ./gdbserver.py MprvTest.test_mprv # Then inspect gdb.log and spike.log to see what happened in more detail. if __name__ == '__main__':