Merge pull request #58 from riscv/fpga_reset_halt
[riscv-tests.git] / debug / gdbserver.py
1 #!/usr/bin/env python
2
3 import argparse
4 import binascii
5 import random
6 import sys
7 import tempfile
8 import time
9 import os
10
11 import targets
12 import testlib
13 from testlib import assertEqual, assertNotEqual, assertIn, assertNotIn
14 from testlib import assertGreater, assertRegexpMatches, assertLess
15 from testlib import GdbTest
16
17 MSTATUS_UIE = 0x00000001
18 MSTATUS_SIE = 0x00000002
19 MSTATUS_HIE = 0x00000004
20 MSTATUS_MIE = 0x00000008
21 MSTATUS_UPIE = 0x00000010
22 MSTATUS_SPIE = 0x00000020
23 MSTATUS_HPIE = 0x00000040
24 MSTATUS_MPIE = 0x00000080
25 MSTATUS_SPP = 0x00000100
26 MSTATUS_HPP = 0x00000600
27 MSTATUS_MPP = 0x00001800
28 MSTATUS_FS = 0x00006000
29 MSTATUS_XS = 0x00018000
30 MSTATUS_MPRV = 0x00020000
31 MSTATUS_PUM = 0x00040000
32 MSTATUS_MXR = 0x00080000
33 MSTATUS_VM = 0x1F000000
34 MSTATUS32_SD = 0x80000000
35 MSTATUS64_SD = 0x8000000000000000
36
37 # pylint: disable=abstract-method
38
39 def ihex_line(address, record_type, data):
40 assert len(data) < 128
41 line = ":%02X%04X%02X" % (len(data), address, record_type)
42 check = len(data)
43 check += address % 256
44 check += address >> 8
45 check += record_type
46 for char in data:
47 value = ord(char)
48 check += value
49 line += "%02X" % value
50 line += "%02X\n" % ((256-check)%256)
51 return line
52
53 def ihex_parse(line):
54 assert line.startswith(":")
55 line = line[1:]
56 data_len = int(line[:2], 16)
57 address = int(line[2:6], 16)
58 record_type = int(line[6:8], 16)
59 data = ""
60 for i in range(data_len):
61 data += "%c" % int(line[8+2*i:10+2*i], 16)
62 return record_type, address, data
63
64 def readable_binary_string(s):
65 return "".join("%02x" % ord(c) for c in s)
66
67 class SimpleRegisterTest(GdbTest):
68 def check_reg(self, name):
69 a = random.randrange(1<<self.target.xlen)
70 b = random.randrange(1<<self.target.xlen)
71 self.gdb.p("$%s=0x%x" % (name, a))
72 self.gdb.stepi()
73 assertEqual(self.gdb.p("$%s" % name), a)
74 self.gdb.p("$%s=0x%x" % (name, b))
75 self.gdb.stepi()
76 assertEqual(self.gdb.p("$%s" % name), b)
77
78 def setup(self):
79 # 0x13 is nop
80 self.gdb.command("p *((int*) 0x%x)=0x13" % self.target.ram)
81 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 4))
82 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 8))
83 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 12))
84 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 16))
85 self.gdb.p("$pc=0x%x" % self.target.ram)
86
87 class SimpleS0Test(SimpleRegisterTest):
88 def test(self):
89 self.check_reg("s0")
90
91 class SimpleS1Test(SimpleRegisterTest):
92 def test(self):
93 self.check_reg("s1")
94
95 class SimpleT0Test(SimpleRegisterTest):
96 def test(self):
97 self.check_reg("t0")
98
99 class SimpleT1Test(SimpleRegisterTest):
100 def test(self):
101 self.check_reg("t1")
102
103 class SimpleF18Test(SimpleRegisterTest):
104 def check_reg(self, name):
105 self.gdb.p_raw("$mstatus=$mstatus | 0x00006000")
106 self.gdb.stepi()
107 a = random.random()
108 b = random.random()
109 self.gdb.p_raw("$%s=%f" % (name, a))
110 self.gdb.stepi()
111 assertLess(abs(float(self.gdb.p_raw("$%s" % name)) - a), .001)
112 self.gdb.p_raw("$%s=%f" % (name, b))
113 self.gdb.stepi()
114 assertLess(abs(float(self.gdb.p_raw("$%s" % name)) - b), .001)
115
116 def early_applicable(self):
117 return self.target.extensionSupported('F')
118
119 def test(self):
120 self.check_reg("f18")
121
122 class SimpleMemoryTest(GdbTest):
123 def access_test(self, size, data_type):
124 assertEqual(self.gdb.p("sizeof(%s)" % data_type), size)
125 a = 0x86753095555aaaa & ((1<<(size*8))-1)
126 b = 0xdeadbeef12345678 & ((1<<(size*8))-1)
127 self.gdb.p("*((%s*)0x%x) = 0x%x" % (data_type, self.target.ram, a))
128 self.gdb.p("*((%s*)0x%x) = 0x%x" % (data_type, self.target.ram + size,
129 b))
130 assertEqual(self.gdb.p("*((%s*)0x%x)" % (data_type, self.target.ram)),
131 a)
132 assertEqual(self.gdb.p("*((%s*)0x%x)" % (
133 data_type, self.target.ram + size)), b)
134
135 class MemTest8(SimpleMemoryTest):
136 def test(self):
137 self.access_test(1, 'char')
138
139 class MemTest16(SimpleMemoryTest):
140 def test(self):
141 self.access_test(2, 'short')
142
143 class MemTest32(SimpleMemoryTest):
144 def test(self):
145 self.access_test(4, 'int')
146
147 class MemTest64(SimpleMemoryTest):
148 def test(self):
149 self.access_test(8, 'long long')
150
151 # FIXME: I'm not passing back invalid addresses correctly in read/write memory.
152 #class MemTestReadInvalid(SimpleMemoryTest):
153 # def test(self):
154 # # This test relies on 'gdb_report_data_abort enable' being executed in
155 # # the openocd.cfg file.
156 # try:
157 # self.gdb.p("*((int*)0xdeadbeef)")
158 # assert False, "Read should have failed."
159 # except testlib.CannotAccess as e:
160 # assertEqual(e.address, 0xdeadbeef)
161 # self.gdb.p("*((int*)0x%x)" % self.target.ram)
162 #
163 #class MemTestWriteInvalid(SimpleMemoryTest):
164 # def test(self):
165 # # This test relies on 'gdb_report_data_abort enable' being executed in
166 # # the openocd.cfg file.
167 # try:
168 # self.gdb.p("*((int*)0xdeadbeef)=8675309")
169 # assert False, "Write should have failed."
170 # except testlib.CannotAccess as e:
171 # assertEqual(e.address, 0xdeadbeef)
172 # self.gdb.p("*((int*)0x%x)=6874742" % self.target.ram)
173
174 class MemTestBlock(GdbTest):
175 def test(self):
176 length = 1024
177 line_length = 16
178 a = tempfile.NamedTemporaryFile(suffix=".ihex")
179 data = ""
180 for i in range(length / line_length):
181 line_data = "".join(["%c" % random.randrange(256)
182 for _ in range(line_length)])
183 data += line_data
184 a.write(ihex_line(i * line_length, 0, line_data))
185 a.flush()
186
187 self.gdb.command("restore %s 0x%x" % (a.name, self.target.ram))
188 for offset in range(0, length, 19*4) + [length-4]:
189 value = self.gdb.p("*((int*)0x%x)" % (self.target.ram + offset))
190 written = ord(data[offset]) | \
191 (ord(data[offset+1]) << 8) | \
192 (ord(data[offset+2]) << 16) | \
193 (ord(data[offset+3]) << 24)
194 assertEqual(value, written)
195
196 b = tempfile.NamedTemporaryFile(suffix=".ihex")
197 self.gdb.command("dump ihex memory %s 0x%x 0x%x" % (b.name,
198 self.target.ram, self.target.ram + length))
199 for line in b:
200 record_type, address, line_data = ihex_parse(line)
201 if record_type == 0:
202 assertEqual(readable_binary_string(line_data),
203 readable_binary_string(
204 data[address:address+len(line_data)]))
205
206 class InstantHaltTest(GdbTest):
207 def test(self):
208 """Assert that reset is really resetting what it should."""
209 self.gdb.command("monitor reset halt")
210 self.gdb.command("flushregs")
211 assertEqual(self.target.reset_vector, self.gdb.p("$pc"))
212 # mcycle and minstret have no defined reset value.
213 mstatus = self.gdb.p("$mstatus")
214 assertEqual(mstatus & (MSTATUS_MIE | MSTATUS_MPRV |
215 MSTATUS_VM), 0)
216
217 class InstantChangePc(GdbTest):
218 def test(self):
219 """Change the PC right as we come out of reset."""
220 # 0x13 is nop
221 self.gdb.command("monitor reset halt")
222 self.gdb.command("flushregs")
223 self.gdb.command("p *((int*) 0x%x)=0x13" % self.target.ram)
224 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 4))
225 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 8))
226 self.gdb.p("$pc=0x%x" % self.target.ram)
227 self.gdb.stepi()
228 assertEqual((self.target.ram + 4), self.gdb.p("$pc"))
229 self.gdb.stepi()
230 assertEqual((self.target.ram + 8), self.gdb.p("$pc"))
231
232 class DebugTest(GdbTest):
233 # Include malloc so that gdb can make function calls. I suspect this malloc
234 # will silently blow through the memory set aside for it, so be careful.
235 compile_args = ("programs/debug.c", "programs/checksum.c",
236 "programs/tiny-malloc.c", "-DDEFINE_MALLOC", "-DDEFINE_FREE")
237
238 def setup(self):
239 self.gdb.load()
240 self.gdb.b("_exit")
241
242 def exit(self, expected_result=0xc86455d4):
243 output = self.gdb.c()
244 assertIn("Breakpoint", output)
245 assertIn("_exit", output)
246 assertEqual(self.gdb.p("status"), expected_result)
247
248 class DebugCompareSections(DebugTest):
249 def test(self):
250 output = self.gdb.command("compare-sections")
251 matched = 0
252 for line in output.splitlines():
253 if line.startswith("Section"):
254 assert line.endswith("matched.")
255 matched += 1
256 assertGreater(matched, 1)
257
258 class DebugFunctionCall(DebugTest):
259 def test(self):
260 self.gdb.b("main:start")
261 self.gdb.c()
262 assertEqual(self.gdb.p('fib(6)'), 8)
263 assertEqual(self.gdb.p('fib(7)'), 13)
264 self.exit()
265
266 class DebugChangeString(DebugTest):
267 def test(self):
268 text = "This little piggy went to the market."
269 self.gdb.b("main:start")
270 self.gdb.c()
271 self.gdb.p('fox = "%s"' % text)
272 self.exit(0x43b497b8)
273
274 class DebugTurbostep(DebugTest):
275 def test(self):
276 """Single step a bunch of times."""
277 self.gdb.b("main:start")
278 self.gdb.c()
279 self.gdb.command("p i=0")
280 last_pc = None
281 advances = 0
282 jumps = 0
283 for _ in range(10):
284 self.gdb.stepi()
285 pc = self.gdb.p("$pc")
286 assertNotEqual(last_pc, pc)
287 if last_pc and pc > last_pc and pc - last_pc <= 4:
288 advances += 1
289 else:
290 jumps += 1
291 last_pc = pc
292 # Some basic sanity that we're not running between breakpoints or
293 # something.
294 assertGreater(jumps, 1)
295 assertGreater(advances, 5)
296
297 class DebugExit(DebugTest):
298 def test(self):
299 self.exit()
300
301 class DebugSymbols(DebugTest):
302 def test(self):
303 self.gdb.b("main")
304 self.gdb.b("rot13")
305 output = self.gdb.c()
306 assertIn(", main ", output)
307 output = self.gdb.c()
308 assertIn(", rot13 ", output)
309
310 class DebugBreakpoint(DebugTest):
311 def test(self):
312 self.gdb.b("rot13")
313 # The breakpoint should be hit exactly 2 times.
314 for _ in range(2):
315 output = self.gdb.c()
316 self.gdb.p("$pc")
317 assertIn("Breakpoint ", output)
318 assertIn("rot13 ", output)
319 self.exit()
320
321 class Hwbp1(DebugTest):
322 def test(self):
323 if self.target.instruction_hardware_breakpoint_count < 1:
324 return 'not_applicable'
325
326 self.gdb.hbreak("rot13")
327 # The breakpoint should be hit exactly 2 times.
328 for _ in range(2):
329 output = self.gdb.c()
330 self.gdb.p("$pc")
331 assertRegexpMatches(output, r"[bB]reakpoint")
332 assertIn("rot13 ", output)
333 self.exit()
334
335 class Hwbp2(DebugTest):
336 def test(self):
337 if self.target.instruction_hardware_breakpoint_count < 2:
338 return 'not_applicable'
339
340 self.gdb.hbreak("main")
341 self.gdb.hbreak("rot13")
342 # We should hit 3 breakpoints.
343 for expected in ("main", "rot13", "rot13"):
344 output = self.gdb.c()
345 self.gdb.p("$pc")
346 assertRegexpMatches(output, r"[bB]reakpoint")
347 assertIn("%s " % expected, output)
348 self.exit()
349
350 class TooManyHwbp(DebugTest):
351 def run(self):
352 for i in range(30):
353 self.gdb.hbreak("*rot13 + %d" % (i * 4))
354
355 output = self.gdb.c()
356 assertIn("Cannot insert hardware breakpoint", output)
357 # Clean up, otherwise the hardware breakpoints stay set and future
358 # tests may fail.
359 self.gdb.command("D")
360
361 class Registers(DebugTest):
362 def test(self):
363 # Get to a point in the code where some registers have actually been
364 # used.
365 self.gdb.b("rot13")
366 self.gdb.c()
367 self.gdb.c()
368 # Try both forms to test gdb.
369 for cmd in ("info all-registers", "info registers all"):
370 output = self.gdb.command(cmd)
371 for reg in ('zero', 'ra', 'sp', 'gp', 'tp'):
372 assertIn(reg, output)
373
374 #TODO
375 # mcpuid is one of the few registers that should have the high bit set
376 # (for rv64).
377 # Leave this commented out until gdb and spike agree on the encoding of
378 # mcpuid (which is going to be renamed to misa in any case).
379 #assertRegexpMatches(output, ".*mcpuid *0x80")
380
381 #TODO:
382 # The instret register should always be changing.
383 #last_instret = None
384 #for _ in range(5):
385 # instret = self.gdb.p("$instret")
386 # assertNotEqual(instret, last_instret)
387 # last_instret = instret
388 # self.gdb.stepi()
389
390 self.exit()
391
392 class UserInterrupt(DebugTest):
393 def test(self):
394 """Sending gdb ^C while the program is running should cause it to
395 halt."""
396 self.gdb.b("main:start")
397 self.gdb.c()
398 self.gdb.p("i=123")
399 self.gdb.c(wait=False)
400 time.sleep(0.5)
401 output = self.gdb.interrupt()
402 assert "main" in output
403 assertGreater(self.gdb.p("j"), 10)
404 self.gdb.p("i=0")
405 self.exit()
406
407 class MulticoreTest(GdbTest):
408 compile_args = ("programs/infinite_loop.S", )
409
410 def setup(self):
411 self.gdb.load()
412 self.gdb.b("main")
413 self.gdb.b("main_end")
414 self.gdb.command("set non-stop on")
415 self.gdb.c()
416
417 def test(self):
418 threads = self.gdb.threads()
419 if len(threads) < 2:
420 return 'not_applicable'
421 # Run through the entire loop.
422 for t in threads:
423 self.gdb.thread(t)
424 self.gdb.p("$pc=_start")
425 # Run to main
426 for t in threads:
427 self.gdb.thread(t)
428 self.gdb.c()
429 for t in self.gdb.threads():
430 assertIn("main", t.frame)
431 # Run to end
432 for t in threads:
433 self.gdb.thread(t)
434 self.gdb.c()
435 hart_ids = []
436 for t in self.gdb.threads():
437 assertIn("main_end", t.frame)
438 # Check register values.
439 self.gdb.thread(t)
440 hart_id = self.gdb.p("$x1")
441 assertNotIn(hart_id, hart_ids)
442 hart_ids.append(hart_id)
443 for n in range(2, 32):
444 value = self.gdb.p("$x%d" % n)
445 assertEqual(value, hart_ids[-1] + n - 1)
446
447 # Confirmed that we read different register values for different harts.
448 # Write a new value to x1, and run through the add sequence again.
449
450 # This part isn't working right, because gdb doesn't resume Thread 2
451 # when asked. I don't know the root cause for that, but up to this
452 # point the test is still useful.
453
454 # for t in threads:
455 # self.gdb.thread(t)
456 # self.gdb.p("$x1=0x%x" % (int(t.id) + 0x800))
457 # self.gdb.p("$pc=main_post_csrr")
458 # for t in threads:
459 # self.gdb.thread(t)
460 # self.gdb.c()
461 # for t in self.gdb.threads():
462 # assertIn("main_end", t.frame)
463 # # Check register values.
464 # self.gdb.thread(t)
465 # for n in range(1, 32):
466 # value = self.gdb.p("$x%d" % n)
467 # assertEqual(value, int(t.id) + 0x800 + n - 1)
468
469 class StepTest(GdbTest):
470 compile_args = ("programs/step.S", )
471
472 def setup(self):
473 self.gdb.load()
474 self.gdb.b("main")
475 self.gdb.c()
476
477 def test(self):
478 main_address = self.gdb.p("$pc")
479 if self.target.extensionSupported("c"):
480 sequence = (4, 8, 0xc, 0xe, 0x14, 0x18, 0x22, 0x1c, 0x24, 0x24)
481 else:
482 sequence = (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c)
483 for expected in sequence:
484 self.gdb.stepi()
485 pc = self.gdb.p("$pc")
486 assertEqual("%x" % (pc - main_address), "%x" % expected)
487
488 class TriggerTest(GdbTest):
489 compile_args = ("programs/trigger.S", )
490 def setup(self):
491 self.gdb.load()
492 self.gdb.b("_exit")
493 self.gdb.b("main")
494 self.gdb.c()
495
496 def exit(self):
497 output = self.gdb.c()
498 assertIn("Breakpoint", output)
499 assertIn("_exit", output)
500
501 class TriggerExecuteInstant(TriggerTest):
502 """Test an execute breakpoint on the first instruction executed out of
503 debug mode."""
504 def test(self):
505 main_address = self.gdb.p("$pc")
506 self.gdb.command("hbreak *0x%x" % (main_address + 4))
507 self.gdb.c()
508 assertEqual(self.gdb.p("$pc"), main_address+4)
509
510 # FIXME: Triggers aren't quite working yet
511 #class TriggerLoadAddress(TriggerTest):
512 # def test(self):
513 # self.gdb.command("rwatch *((&data)+1)")
514 # output = self.gdb.c()
515 # assertIn("read_loop", output)
516 # assertEqual(self.gdb.p("$a0"),
517 # self.gdb.p("(&data)+1"))
518 # self.exit()
519
520 class TriggerLoadAddressInstant(TriggerTest):
521 """Test a load address breakpoint on the first instruction executed out of
522 debug mode."""
523 def test(self):
524 self.gdb.command("b just_before_read_loop")
525 self.gdb.c()
526 read_loop = self.gdb.p("&read_loop")
527 self.gdb.command("rwatch data")
528 self.gdb.c()
529 # Accept hitting the breakpoint before or after the load instruction.
530 assertIn(self.gdb.p("$pc"), [read_loop, read_loop + 4])
531 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
532
533 # FIXME: Triggers aren't quite working yet
534 #class TriggerStoreAddress(TriggerTest):
535 # def test(self):
536 # self.gdb.command("watch *((&data)+3)")
537 # output = self.gdb.c()
538 # assertIn("write_loop", output)
539 # assertEqual(self.gdb.p("$a0"),
540 # self.gdb.p("(&data)+3"))
541 # self.exit()
542
543 class TriggerStoreAddressInstant(TriggerTest):
544 def test(self):
545 """Test a store address breakpoint on the first instruction executed out
546 of debug mode."""
547 self.gdb.command("b just_before_write_loop")
548 self.gdb.c()
549 write_loop = self.gdb.p("&write_loop")
550 self.gdb.command("watch data")
551 self.gdb.c()
552 # Accept hitting the breakpoint before or after the store instruction.
553 assertIn(self.gdb.p("$pc"), [write_loop, write_loop + 4])
554 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
555
556 class TriggerDmode(TriggerTest):
557 def check_triggers(self, tdata1_lsbs, tdata2):
558 dmode = 1 << (self.target.xlen-5)
559
560 triggers = []
561
562 if self.target.xlen == 32:
563 xlen_type = 'int'
564 elif self.target.xlen == 64:
565 xlen_type = 'long long'
566 else:
567 raise NotImplementedError
568
569 dmode_count = 0
570 i = 0
571 for i in range(16):
572 tdata1 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i))
573 if tdata1 == 0:
574 break
575 tdata2 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i+1))
576
577 if tdata1 & dmode:
578 dmode_count += 1
579 else:
580 assertEqual(tdata1 & 0xffff, tdata1_lsbs)
581 assertEqual(tdata2, tdata2)
582
583 assertGreater(i, 1)
584 assertEqual(dmode_count, 1)
585
586 return triggers
587
588 def test(self):
589 self.gdb.command("hbreak write_load_trigger")
590 self.gdb.b("clear_triggers")
591 self.gdb.p("$pc=write_store_trigger")
592 output = self.gdb.c()
593 assertIn("write_load_trigger", output)
594 self.check_triggers((1<<6) | (1<<1), 0xdeadbee0)
595 output = self.gdb.c()
596 assertIn("clear_triggers", output)
597 self.check_triggers((1<<6) | (1<<0), 0xfeedac00)
598
599 class RegsTest(GdbTest):
600 compile_args = ("programs/regs.S", )
601 def setup(self):
602 self.gdb.load()
603 self.gdb.b("main")
604 self.gdb.b("handle_trap")
605 self.gdb.c()
606
607 class WriteGprs(RegsTest):
608 def test(self):
609 regs = [("x%d" % n) for n in range(2, 32)]
610
611 self.gdb.p("$pc=write_regs")
612 for i, r in enumerate(regs):
613 self.gdb.p("$%s=%d" % (r, (0xdeadbeef<<i)+17))
614 self.gdb.p("$x1=data")
615 self.gdb.command("b all_done")
616 output = self.gdb.c()
617 assertIn("Breakpoint ", output)
618
619 # Just to get this data in the log.
620 self.gdb.command("x/30gx data")
621 self.gdb.command("info registers")
622 for n in range(len(regs)):
623 assertEqual(self.gdb.x("data+%d" % (8*n), 'g'),
624 ((0xdeadbeef<<n)+17) & ((1<<self.target.xlen)-1))
625
626 class WriteCsrs(RegsTest):
627 def test(self):
628 # As much a test of gdb as of the simulator.
629 self.gdb.p("$mscratch=0")
630 self.gdb.stepi()
631 assertEqual(self.gdb.p("$mscratch"), 0)
632 self.gdb.p("$mscratch=123")
633 self.gdb.stepi()
634 assertEqual(self.gdb.p("$mscratch"), 123)
635
636 self.gdb.p("$pc=write_regs")
637 self.gdb.p("$x1=data")
638 self.gdb.command("b all_done")
639 self.gdb.command("c")
640
641 assertEqual(123, self.gdb.p("$mscratch"))
642 assertEqual(123, self.gdb.p("$x1"))
643 assertEqual(123, self.gdb.p("$csr832"))
644
645 class DownloadTest(GdbTest):
646 def setup(self):
647 # pylint: disable=attribute-defined-outside-init
648 length = min(2**10, self.target.ram_size - 2048)
649 self.download_c = tempfile.NamedTemporaryFile(prefix="download_",
650 suffix=".c", delete=False)
651 self.download_c.write("#include <stdint.h>\n")
652 self.download_c.write(
653 "unsigned int crc32a(uint8_t *message, unsigned int size);\n")
654 self.download_c.write("uint32_t length = %d;\n" % length)
655 self.download_c.write("uint8_t d[%d] = {\n" % length)
656 self.crc = 0
657 assert length % 16 == 0
658 for i in range(length / 16):
659 self.download_c.write(" /* 0x%04x */ " % (i * 16))
660 for _ in range(16):
661 value = random.randrange(1<<8)
662 self.download_c.write("0x%02x, " % value)
663 self.crc = binascii.crc32("%c" % value, self.crc)
664 self.download_c.write("\n")
665 self.download_c.write("};\n")
666 self.download_c.write("uint8_t *data = &d[0];\n")
667 self.download_c.write(
668 "uint32_t main() { return crc32a(data, length); }\n")
669 self.download_c.flush()
670
671 if self.crc < 0:
672 self.crc += 2**32
673
674 self.binary = self.target.compile(self.download_c.name,
675 "programs/checksum.c")
676 self.gdb.command("file %s" % self.binary)
677
678 def test(self):
679 self.gdb.load()
680 self.gdb.command("b _exit")
681 self.gdb.c(timeout=60)
682 assertEqual(self.gdb.p("status"), self.crc)
683 os.unlink(self.download_c.name)
684
685 # FIXME: PRIV isn't implemented in the current OpenOCD
686 #class MprvTest(GdbTest):
687 # compile_args = ("programs/mprv.S", )
688 # def setup(self):
689 # self.gdb.load()
690 #
691 # def test(self):
692 # """Test that the debugger can access memory when MPRV is set."""
693 # self.gdb.c(wait=False)
694 # time.sleep(0.5)
695 # self.gdb.interrupt()
696 # output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)")
697 # assertIn("0xbead", output)
698 #
699 #class PrivTest(GdbTest):
700 # compile_args = ("programs/priv.S", )
701 # def setup(self):
702 # # pylint: disable=attribute-defined-outside-init
703 # self.gdb.load()
704 #
705 # misa = self.target.misa
706 # self.supported = set()
707 # if misa & (1<<20):
708 # self.supported.add(0)
709 # if misa & (1<<18):
710 # self.supported.add(1)
711 # if misa & (1<<7):
712 # self.supported.add(2)
713 # self.supported.add(3)
714 #
715 #class PrivRw(PrivTest):
716 # def test(self):
717 # """Test reading/writing priv."""
718 # for privilege in range(4):
719 # self.gdb.p("$priv=%d" % privilege)
720 # self.gdb.stepi()
721 # actual = self.gdb.p("$priv")
722 # assertIn(actual, self.supported)
723 # if privilege in self.supported:
724 # assertEqual(actual, privilege)
725 #
726 #class PrivChange(PrivTest):
727 # def test(self):
728 # """Test that the core's privilege level actually changes."""
729 #
730 # if 0 not in self.supported:
731 # return 'not_applicable'
732 #
733 # self.gdb.b("main")
734 # self.gdb.c()
735 #
736 # # Machine mode
737 # self.gdb.p("$priv=3")
738 # main_address = self.gdb.p("$pc")
739 # self.gdb.stepi()
740 # assertEqual("%x" % self.gdb.p("$pc"), "%x" % (main_address+4))
741 #
742 # # User mode
743 # self.gdb.p("$priv=0")
744 # self.gdb.stepi()
745 # # Should have taken an exception, so be nowhere near main.
746 # pc = self.gdb.p("$pc")
747 # assertTrue(pc < main_address or pc > main_address + 0x100)
748
749 parsed = None
750 def main():
751 parser = argparse.ArgumentParser(
752 description="Test that gdb can talk to a RISC-V target.",
753 epilog="""
754 Example command line from the real world:
755 Run all RegsTest cases against a physical FPGA, with custom openocd command:
756 ./gdbserver.py --freedom-e300 --server_cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" Simple
757 """)
758 targets.add_target_options(parser)
759
760 testlib.add_test_run_options(parser)
761
762 # TODO: remove global
763 global parsed # pylint: disable=global-statement
764 parsed = parser.parse_args()
765 target = targets.target(parsed)
766
767 if parsed.xlen:
768 target.xlen = parsed.xlen
769
770 module = sys.modules[__name__]
771
772 return testlib.run_all_tests(module, target, parsed)
773
774 # TROUBLESHOOTING TIPS
775 # If a particular test fails, run just that one test, eg.:
776 # ./gdbserver.py MprvTest.test_mprv
777 # Then inspect gdb.log and spike.log to see what happened in more detail.
778
779 if __name__ == '__main__':
780 sys.exit(main())