13 class DeleteServer(unittest
.TestCase
):
17 class MemoryTest(DeleteServer
):
19 self
.server
= target
.server()
20 self
.gdb
= testlib
.Gdb()
21 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
24 self
.gdb
.p("*((int*)0x%x) = 0x8675309" % target
.ram
)
25 self
.gdb
.p("*((int*)0x%x) = 0xdeadbeef" % (target
.ram
+ 4))
26 self
.assertEqual(self
.gdb
.p("*((int*)0x%x)" % target
.ram
), 0x8675309)
27 self
.assertEqual(self
.gdb
.p("*((int*)0x%x)" % (target
.ram
+ 4)), 0xdeadbeef)
29 class InstantHaltTest(DeleteServer
):
31 self
.binary
= target
.compile("programs/debug.c")
32 self
.server
= target
.server(self
.binary
, halted
=True)
33 self
.gdb
= testlib
.Gdb()
34 self
.gdb
.command("file %s" % self
.binary
)
35 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
37 def test_instant_halt(self
):
38 self
.assertEqual(0x1000, self
.gdb
.p("$pc"))
39 # For some reason instret resets to 0.
40 self
.assertLess(self
.gdb
.p("$instret"), 8)
41 self
.gdb
.command("stepi")
42 self
.assertNotEqual(0x1000, self
.gdb
.p("$pc"))
44 def test_change_pc(self
):
45 """Change the PC right as we come out of reset."""
47 self
.gdb
.command("p *((int*) 0x80000000)=0x13")
48 self
.gdb
.command("p *((int*) 0x80000004)=0x13")
49 self
.gdb
.command("p *((int*) 0x80000008)=0x13")
50 self
.gdb
.command("p $pc=0x80000000")
51 self
.gdb
.command("stepi")
52 self
.assertEqual(0x80000004, self
.gdb
.p("$pc"))
53 self
.gdb
.command("stepi")
54 self
.assertEqual(0x80000008, self
.gdb
.p("$pc"))
56 class DebugTest(DeleteServer
):
58 self
.binary
= target
.compile("programs/debug.c", "programs/checksum.c")
59 self
.server
= target
.server()
60 self
.gdb
= testlib
.Gdb()
61 self
.gdb
.command("file %s" % self
.binary
)
62 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
63 self
.gdb
.load(self
.binary
)
68 self
.assertIn("Breakpoint", output
)
69 self
.assertIn("_exit", output
)
70 self
.assertEqual(self
.gdb
.p("status"), 0xc86455d4)
72 def test_turbostep(self
):
73 """Single step a bunch of times."""
74 self
.gdb
.command("p i=0");
77 self
.gdb
.command("stepi")
78 pc
= self
.gdb
.command("p $pc")
79 self
.assertNotEqual(last_pc
, pc
)
85 def test_breakpoint(self
):
87 # The breakpoint should be hit exactly 2 times.
90 self
.assertIn("Breakpoint ", output
)
93 def test_registers(self
):
96 # Try both forms to test gdb.
97 for cmd
in ("info all-registers", "info registers all"):
98 output
= self
.gdb
.command(cmd
)
99 self
.assertNotIn("Could not", output
)
100 for reg
in ('zero', 'ra', 'sp', 'gp', 'tp'):
101 self
.assertIn(reg
, output
)
102 # mcpuid is one of the few registers that should have the high bit set
104 # Leave this commented out until gdb and spike agree on the encoding of
105 # mcpuid (which is going to be renamed to misa in any case).
106 #self.assertRegexpMatches(output, ".*mcpuid *0x80")
108 # The instret register should always be changing.
111 instret
= self
.gdb
.p("$instret")
112 self
.assertNotEqual(instret
, last_instret
)
113 last_instret
= instret
114 self
.gdb
.command("stepi")
118 def test_interrupt(self
):
119 """Sending gdb ^C while the program is running should cause it to halt."""
120 self
.gdb
.b("main:start")
122 self
.gdb
.command("p i=123");
123 self
.gdb
.c(wait
=False)
125 output
= self
.gdb
.interrupt()
126 assert "main" in output
127 self
.assertGreater(self
.gdb
.p("j"), 10)
131 class RegsTest(DeleteServer
):
133 self
.binary
= target
.compile("programs/regs.S")
134 self
.server
= target
.server()
135 self
.gdb
= testlib
.Gdb()
136 self
.gdb
.command("file %s" % self
.binary
)
137 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
138 self
.gdb
.command("load")
140 def test_write_gprs(self
):
141 # Note a0 is missing from this list since it's used to hold the
143 regs
= ("ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1",
144 "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4",
145 "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5",
148 self
.gdb
.command("p $pc=write_regs")
149 for i
, r
in enumerate(regs
):
150 self
.gdb
.command("p $%s=%d" % (r
, (0xdeadbeef<<i
)+17))
151 self
.gdb
.command("p $a0=data")
152 self
.gdb
.command("b all_done")
153 output
= self
.gdb
.command("c")
154 self
.assertIn("Breakpoint 1", output
)
156 # Just to get this data in the log.
157 self
.gdb
.command("x/30gx data")
158 self
.gdb
.command("info registers")
159 for n
in range(len(regs
)):
160 self
.assertEqual(self
.gdb
.x("data+%d" % (8*n
), 'g'),
163 def test_write_csrs(self
):
164 # As much a test of gdb as of the simulator.
165 self
.gdb
.p("$mscratch=0")
167 self
.assertEqual(self
.gdb
.p("$mscratch"), 0)
168 self
.gdb
.p("$mscratch=123")
170 self
.assertEqual(self
.gdb
.p("$mscratch"), 123)
172 self
.gdb
.command("p $fflags=9")
173 self
.gdb
.command("p $pc=write_regs")
174 self
.gdb
.command("p $a0=data")
175 self
.gdb
.command("b all_done")
176 self
.gdb
.command("c")
178 self
.assertEqual(9, self
.gdb
.p("$fflags"))
179 self
.assertEqual(9, self
.gdb
.p("$x1"))
180 self
.assertEqual(9, self
.gdb
.p("$csr1"))
182 class DownloadTest(DeleteServer
):
185 fd
= file("data.c", "w")
186 # extern uint8_t *data;
187 # extern uint32_t length;
191 # /* Compute a simple checksum. */
192 # return crc32a(data, length);
194 fd
.write("#include <stdint.h>\n")
195 fd
.write("uint32_t length = %d;\n" % length
)
196 fd
.write("uint8_t d[%d] = {\n" % length
)
198 for i
in range(length
/ 16):
199 fd
.write(" /* 0x%04x */ " % (i
* 16));
201 value
= random
.randrange(1<<8)
202 fd
.write("%d, " % value
)
203 self
.crc
= binascii
.crc32("%c" % value
, self
.crc
)
206 fd
.write("uint8_t *data = &d[0];\n");
209 self
.binary
= target
.compile("checksum.c", "data.c", "start.S",
211 "-T", "standalone.lds",
214 self
.server
= target
.server(None, halted
=True)
215 self
.gdb
= testlib
.Gdb()
216 self
.gdb
.command("file %s" % self
.binary
)
217 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
219 def test_download(self
):
220 output
= self
.gdb
.command("load")
221 self
.assertNotIn("failed", output
)
222 self
.assertIn("Transfer rate", output
)
223 self
.gdb
.command("b done")
225 result
= self
.gdb
.p("$a0")
226 self
.assertEqual(self
.crc
, result
)
228 class MprvTest(DeleteServer
):
230 self
.binary
= target
.compile("mprv.S", "-T", "standalone.lds",
232 self
.server
= target
.server(None, halted
=True)
233 self
.gdb
= testlib
.Gdb()
234 self
.gdb
.command("file %s" % self
.binary
)
235 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
236 self
.gdb
.command("load")
239 """Test that the debugger can access memory when MPRV is set."""
240 self
.gdb
.c(wait
=False)
242 output
= self
.gdb
.command("p/x *(int*)(((char*)&data)-0x80000000)")
243 self
.assertIn("0xbead", output
)
245 class Target(object):
247 raise NotImplementedError
249 def compile(self
, *sources
):
250 return testlib
.compile(sources
+
251 ("targets/%s/entry.S" % self
.name
, "programs/init.c",
253 "-T", "targets/%s/link.lds" % self
.name
,
255 "-mcmodel=medany"), xlen
=self
.xlen
)
257 class SpikeTarget(Target
):
263 return testlib
.Spike(parsed
.cmd
, halted
=True)
265 class MicroSemiTarget(Target
):
271 return testlib
.Openocd(cmd
=parsed
.cmd
,
272 config
="targets/%s/openocd.cfg" % self
.name
)
280 parser
= argparse
.ArgumentParser()
281 group
= parser
.add_mutually_exclusive_group(required
=True)
283 group
.add_argument("--%s" % t
.name
, action
="store_const", const
=t
,
285 parser
.add_argument("--cmd",
286 help="The command to use to start the debug server.")
287 parser
.add_argument("unittest", nargs
="*")
289 parsed
= parser
.parse_args()
292 target
= parsed
.target()
293 unittest
.main(argv
=[sys
.argv
[0]] + parsed
.unittest
)
295 # TROUBLESHOOTING TIPS
296 # If a particular test fails, run just that one test, eg.:
297 # ./tests/gdbserver.py MprvTest.test_mprv
298 # Then inspect gdb.log and spike.log to see what happened in more detail.
300 if __name__
== '__main__':