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