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