13 from testlib
import assertEqual
, assertNotEqual
, assertIn
, assertNotIn
14 from testlib
import assertGreater
, assertRegexpMatches
, assertLess
15 from testlib
import GdbTest
, GdbSingleHartTest
, TestFailed
16 #from testlib import assertTrue
18 MSTATUS_UIE
= 0x00000001
19 MSTATUS_SIE
= 0x00000002
20 MSTATUS_HIE
= 0x00000004
21 MSTATUS_MIE
= 0x00000008
22 MSTATUS_UPIE
= 0x00000010
23 MSTATUS_SPIE
= 0x00000020
24 MSTATUS_HPIE
= 0x00000040
25 MSTATUS_MPIE
= 0x00000080
26 MSTATUS_SPP
= 0x00000100
27 MSTATUS_HPP
= 0x00000600
28 MSTATUS_MPP
= 0x00001800
29 MSTATUS_FS
= 0x00006000
30 MSTATUS_XS
= 0x00018000
31 MSTATUS_MPRV
= 0x00020000
32 MSTATUS_PUM
= 0x00040000
33 MSTATUS_MXR
= 0x00080000
34 MSTATUS_VM
= 0x1F000000
35 MSTATUS32_SD
= 0x80000000
36 MSTATUS64_SD
= 0x8000000000000000
38 # pylint: disable=abstract-method
40 def ihex_line(address
, record_type
, data
):
41 assert len(data
) < 128
42 line
= ":%02X%04X%02X" % (len(data
), address
, record_type
)
44 check
+= address
% 256
50 line
+= "%02X" % value
51 line
+= "%02X\n" % ((256-check
)%256)
55 assert line
.startswith(":")
57 data_len
= int(line
[:2], 16)
58 address
= int(line
[2:6], 16)
59 record_type
= int(line
[6:8], 16)
61 for i
in range(data_len
):
62 data
+= "%c" % int(line
[8+2*i
:10+2*i
], 16)
63 return record_type
, address
, data
65 def readable_binary_string(s
):
66 return "".join("%02x" % ord(c
) for c
in s
)
68 class SimpleRegisterTest(GdbTest
):
69 def check_reg(self
, name
, alias
):
70 a
= random
.randrange(1<<self
.hart
.xlen
)
71 b
= random
.randrange(1<<self
.hart
.xlen
)
72 self
.gdb
.p("$%s=0x%x" % (name
, a
))
73 assertEqual(self
.gdb
.p("$%s" % alias
), a
)
75 assertEqual(self
.gdb
.p("$%s" % name
), a
)
76 assertEqual(self
.gdb
.p("$%s" % alias
), a
)
77 self
.gdb
.p("$%s=0x%x" % (alias
, b
))
78 assertEqual(self
.gdb
.p("$%s" % name
), b
)
80 assertEqual(self
.gdb
.p("$%s" % name
), b
)
81 assertEqual(self
.gdb
.p("$%s" % alias
), b
)
85 self
.gdb
.command("p *((int*) 0x%x)=0x13" % self
.hart
.ram
)
86 self
.gdb
.command("p *((int*) 0x%x)=0x13" % (self
.hart
.ram
+ 4))
87 self
.gdb
.command("p *((int*) 0x%x)=0x13" % (self
.hart
.ram
+ 8))
88 self
.gdb
.command("p *((int*) 0x%x)=0x13" % (self
.hart
.ram
+ 12))
89 self
.gdb
.command("p *((int*) 0x%x)=0x13" % (self
.hart
.ram
+ 16))
90 self
.gdb
.p("$pc=0x%x" % self
.hart
.ram
)
92 class SimpleS0Test(SimpleRegisterTest
):
94 self
.check_reg("s0", "x8")
96 class SimpleS1Test(SimpleRegisterTest
):
98 self
.check_reg("s1", "x9")
100 class SimpleT0Test(SimpleRegisterTest
):
102 self
.check_reg("t0", "x5")
104 class SimpleT1Test(SimpleRegisterTest
):
106 self
.check_reg("t1", "x6")
108 class SimpleF18Test(SimpleRegisterTest
):
109 def check_reg(self
, name
, alias
):
110 if self
.hart
.extensionSupported('F'):
111 self
.gdb
.p_raw("$mstatus=$mstatus | 0x00006000")
115 self
.gdb
.p_raw("$%s=%f" % (name
, a
))
116 assertLess(abs(float(self
.gdb
.p_raw("$%s" % alias
)) - a
), .001)
118 assertLess(abs(float(self
.gdb
.p_raw("$%s" % name
)) - a
), .001)
119 assertLess(abs(float(self
.gdb
.p_raw("$%s" % alias
)) - a
), .001)
120 self
.gdb
.p_raw("$%s=%f" % (alias
, b
))
121 assertLess(abs(float(self
.gdb
.p_raw("$%s" % name
)) - b
), .001)
123 assertLess(abs(float(self
.gdb
.p_raw("$%s" % name
)) - b
), .001)
124 assertLess(abs(float(self
.gdb
.p_raw("$%s" % alias
)) - b
), .001)
126 size
= self
.gdb
.p("sizeof($%s)" % name
)
127 if self
.hart
.extensionSupported('D'):
132 output
= self
.gdb
.p_raw("$" + name
)
133 assertEqual(output
, "void")
134 output
= self
.gdb
.p_raw("$" + alias
)
135 assertEqual(output
, "void")
138 self
.check_reg("f18", "fs2")
140 class CustomRegisterTest(SimpleRegisterTest
):
141 def early_applicable(self
):
142 return self
.target
.implements_custom_test
144 def check_custom(self
, magic
):
145 regs
= self
.gdb
.info_registers("custom")
146 assertEqual(set(regs
.keys()),
152 for name
, value
in regs
.iteritems():
153 number
= int(name
[6:])
155 expect
= number
+ magic
156 assertIn(value
, (expect
, expect
+ (1<<32)))
158 assertIn("Could not fetch register", value
)
165 self
.gdb
.p("$custom12345=%d" % (12345 + magic
))
168 self
.check_custom(magic
)
170 class SimpleNoExistTest(GdbTest
):
173 self
.gdb
.p("$csr2288")
174 assert False, "Reading csr2288 should have failed"
175 except testlib
.CouldNotFetch
:
178 self
.gdb
.p("$csr2288=5")
179 assert False, "Writing csr2288 should have failed"
180 except testlib
.CouldNotFetch
:
183 class SimpleMemoryTest(GdbTest
):
184 def access_test(self
, size
, data_type
):
185 assertEqual(self
.gdb
.p("sizeof(%s)" % data_type
), size
)
186 a
= 0x86753095555aaaa & ((1<<(size
*8))-1)
187 b
= 0xdeadbeef12345678 & ((1<<(size
*8))-1)
188 addrA
= self
.hart
.ram
189 addrB
= self
.hart
.ram
+ self
.hart
.ram_size
- size
190 self
.gdb
.p("*((%s*)0x%x) = 0x%x" % (data_type
, addrA
, a
))
191 self
.gdb
.p("*((%s*)0x%x) = 0x%x" % (data_type
, addrB
, b
))
192 assertEqual(self
.gdb
.p("*((%s*)0x%x)" % (data_type
, addrA
)), a
)
193 assertEqual(self
.gdb
.p("*((%s*)0x%x)" % (data_type
, addrB
)), b
)
195 class MemTest8(SimpleMemoryTest
):
197 self
.access_test(1, 'char')
199 class MemTest16(SimpleMemoryTest
):
201 self
.access_test(2, 'short')
203 class MemTest32(SimpleMemoryTest
):
205 self
.access_test(4, 'int')
207 class MemTest64(SimpleMemoryTest
):
209 self
.access_test(8, 'long long')
211 # FIXME: I'm not passing back invalid addresses correctly in read/write memory.
212 #class MemTestReadInvalid(SimpleMemoryTest):
214 # # This test relies on 'gdb_report_data_abort enable' being executed in
215 # # the openocd.cfg file.
217 # self.gdb.p("*((int*)0xdeadbeef)")
218 # assert False, "Read should have failed."
219 # except testlib.CannotAccess as e:
220 # assertEqual(e.address, 0xdeadbeef)
221 # self.gdb.p("*((int*)0x%x)" % self.hart.ram)
223 #class MemTestWriteInvalid(SimpleMemoryTest):
225 # # This test relies on 'gdb_report_data_abort enable' being executed in
226 # # the openocd.cfg file.
228 # self.gdb.p("*((int*)0xdeadbeef)=8675309")
229 # assert False, "Write should have failed."
230 # except testlib.CannotAccess as e:
231 # assertEqual(e.address, 0xdeadbeef)
232 # self.gdb.p("*((int*)0x%x)=6874742" % self.hart.ram)
234 class MemTestBlock(GdbTest
):
239 a
= tempfile
.NamedTemporaryFile(suffix
=".ihex")
241 for i
in range(self
.length
/ self
.line_length
):
242 line_data
= "".join(["%c" % random
.randrange(256)
243 for _
in range(self
.line_length
)])
245 a
.write(ihex_line(i
* self
.line_length
, 0, line_data
))
248 self
.gdb
.command("shell cat %s" % a
.name
)
249 self
.gdb
.command("restore %s 0x%x" % (a
.name
, self
.hart
.ram
))
251 for offset
in range(0, self
.length
, increment
) + [self
.length
-4]:
252 value
= self
.gdb
.p("*((int*)0x%x)" % (self
.hart
.ram
+ offset
))
253 written
= ord(data
[offset
]) | \
254 (ord(data
[offset
+1]) << 8) | \
255 (ord(data
[offset
+2]) << 16) | \
256 (ord(data
[offset
+3]) << 24)
257 assertEqual(value
, written
)
259 b
= tempfile
.NamedTemporaryFile(suffix
=".ihex")
260 self
.gdb
.command("dump ihex memory %s 0x%x 0x%x" % (b
.name
,
261 self
.hart
.ram
, self
.hart
.ram
+ self
.length
))
262 self
.gdb
.command("shell cat %s" % b
.name
)
263 for line
in b
.xreadlines():
264 record_type
, address
, line_data
= ihex_parse(line
)
266 written_data
= data
[address
:address
+len(line_data
)]
267 if line_data
!= written_data
:
269 "Data mismatch at 0x%x; wrote %s but read %s" % (
270 address
, readable_binary_string(written_data
),
271 readable_binary_string(line_data
)))
273 class InstantHaltTest(GdbTest
):
275 """Assert that reset is really resetting what it should."""
276 self
.gdb
.command("monitor reset halt")
277 self
.gdb
.command("flushregs")
278 threads
= self
.gdb
.threads()
282 pcs
.append(self
.gdb
.p("$pc"))
284 assertIn(pc
, self
.hart
.reset_vectors
)
285 # mcycle and minstret have no defined reset value.
286 mstatus
= self
.gdb
.p("$mstatus")
287 assertEqual(mstatus
& (MSTATUS_MIE | MSTATUS_MPRV |
290 class InstantChangePc(GdbTest
):
292 """Change the PC right as we come out of reset."""
294 self
.gdb
.command("monitor reset halt")
295 self
.gdb
.command("flushregs")
296 self
.gdb
.command("p *((int*) 0x%x)=0x13" % self
.hart
.ram
)
297 self
.gdb
.command("p *((int*) 0x%x)=0x13" % (self
.hart
.ram
+ 4))
298 self
.gdb
.command("p *((int*) 0x%x)=0x13" % (self
.hart
.ram
+ 8))
299 self
.gdb
.p("$pc=0x%x" % self
.hart
.ram
)
301 assertEqual((self
.hart
.ram
+ 4), self
.gdb
.p("$pc"))
303 assertEqual((self
.hart
.ram
+ 8), self
.gdb
.p("$pc"))
305 class DebugTest(GdbSingleHartTest
):
306 # Include malloc so that gdb can make function calls. I suspect this malloc
307 # will silently blow through the memory set aside for it, so be careful.
308 compile_args
= ("programs/debug.c", "programs/checksum.c",
309 "programs/tiny-malloc.c", "-DDEFINE_MALLOC", "-DDEFINE_FREE")
315 def exit(self
, expected_result
=0xc86455d4):
316 output
= self
.gdb
.c()
317 assertIn("Breakpoint", output
)
318 assertIn("_exit", output
)
319 assertEqual(self
.gdb
.p("status"), expected_result
)
321 class DebugCompareSections(DebugTest
):
323 output
= self
.gdb
.command("compare-sections")
325 for line
in output
.splitlines():
326 if line
.startswith("Section"):
327 assert line
.endswith("matched.")
329 assertGreater(matched
, 1)
331 class DebugFunctionCall(DebugTest
):
333 self
.gdb
.b("main:start")
335 assertEqual(self
.gdb
.p('fib(6)'), 8)
336 assertEqual(self
.gdb
.p('fib(7)'), 13)
339 class DebugChangeString(DebugTest
):
341 text
= "This little piggy went to the market."
342 self
.gdb
.b("main:start")
344 self
.gdb
.p('fox = "%s"' % text
)
345 self
.exit(0x43b497b8)
347 class DebugTurbostep(DebugTest
):
349 """Single step a bunch of times."""
350 self
.gdb
.b("main:start")
352 self
.gdb
.command("p i=0")
358 pc
= self
.gdb
.p("$pc")
359 assertNotEqual(last_pc
, pc
)
360 if last_pc
and pc
> last_pc
and pc
- last_pc
<= 4:
365 # Some basic sanity that we're not running between breakpoints or
367 assertGreater(jumps
, 1)
368 assertGreater(advances
, 5)
370 class DebugExit(DebugTest
):
374 class DebugSymbols(DebugTest
):
378 output
= self
.gdb
.c()
379 assertIn(", main ", output
)
380 output
= self
.gdb
.c()
381 assertIn(", rot13 ", output
)
383 class DebugBreakpoint(DebugTest
):
386 # The breakpoint should be hit exactly 2 times.
388 output
= self
.gdb
.c()
390 assertIn("Breakpoint ", output
)
391 assertIn("rot13 ", output
)
394 class Hwbp1(DebugTest
):
396 if self
.hart
.instruction_hardware_breakpoint_count
< 1:
397 return 'not_applicable'
399 if not self
.hart
.honors_tdata1_hmode
:
400 # Run to main before setting the breakpoint, because startup code
401 # will otherwise clear the trigger that we set.
405 self
.gdb
.hbreak("rot13")
406 # The breakpoint should be hit exactly 2 times.
408 output
= self
.gdb
.c()
410 assertRegexpMatches(output
, r
"[bB]reakpoint")
411 assertIn("rot13 ", output
)
414 class Hwbp2(DebugTest
):
416 if self
.hart
.instruction_hardware_breakpoint_count
< 2:
417 return 'not_applicable'
419 self
.gdb
.hbreak("main")
420 self
.gdb
.hbreak("rot13")
421 # We should hit 3 breakpoints.
422 for expected
in ("main", "rot13", "rot13"):
423 output
= self
.gdb
.c()
425 assertRegexpMatches(output
, r
"[bB]reakpoint")
426 assertIn("%s " % expected
, output
)
429 class TooManyHwbp(DebugTest
):
432 self
.gdb
.hbreak("*rot13 + %d" % (i
* 4))
434 output
= self
.gdb
.c()
435 assertIn("Cannot insert hardware breakpoint", output
)
436 # Clean up, otherwise the hardware breakpoints stay set and future
438 self
.gdb
.command("D")
440 class Registers(DebugTest
):
442 # Get to a point in the code where some registers have actually been
447 # Try both forms to test gdb.
448 for cmd
in ("info all-registers", "info registers all"):
449 output
= self
.gdb
.command(cmd
)
450 for reg
in ('zero', 'ra', 'sp', 'gp', 'tp'):
451 assertIn(reg
, output
)
452 for line
in output
.splitlines():
453 assertRegexpMatches(line
, r
"^\S")
456 # mcpuid is one of the few registers that should have the high bit set
458 # Leave this commented out until gdb and spike agree on the encoding of
459 # mcpuid (which is going to be renamed to misa in any case).
460 #assertRegexpMatches(output, ".*mcpuid *0x80")
463 # The instret register should always be changing.
466 # instret = self.gdb.p("$instret")
467 # assertNotEqual(instret, last_instret)
468 # last_instret = instret
473 class UserInterrupt(DebugTest
):
475 """Sending gdb ^C while the program is running should cause it to
477 self
.gdb
.b("main:start")
480 self
.gdb
.c(wait
=False)
482 output
= self
.gdb
.interrupt()
483 assert "main" in output
484 assertGreater(self
.gdb
.p("j"), 10)
488 class InterruptTest(GdbSingleHartTest
):
489 compile_args
= ("programs/interrupt.c",)
491 def early_applicable(self
):
492 return self
.target
.supports_clint_mtime
499 output
= self
.gdb
.c()
500 assertIn(" main ", output
)
501 self
.gdb
.b("trap_entry")
502 output
= self
.gdb
.c()
503 assertIn(" trap_entry ", output
)
504 assertEqual(self
.gdb
.p("$mip") & 0x80, 0x80)
505 assertEqual(self
.gdb
.p("interrupt_count"), 0)
506 # You'd expect local to still be 0, but it looks like spike doesn't
507 # jump to the interrupt handler immediately after the write to
509 assertLess(self
.gdb
.p("local"), 1000)
510 self
.gdb
.command("delete breakpoints")
512 self
.gdb
.c(wait
=False)
515 interrupt_count
= self
.gdb
.p("interrupt_count")
516 local
= self
.gdb
.p("local")
517 if interrupt_count
> 1000 and \
521 assertGreater(interrupt_count
, 1000)
522 assertGreater(local
, 1000)
524 def postMortem(self
):
525 GdbSingleHartTest
.postMortem(self
)
526 self
.gdb
.p("*((long long*) 0x200bff8)")
527 self
.gdb
.p("*((long long*) 0x2004000)")
528 self
.gdb
.p("interrupt_count")
531 class MulticoreRegTest(GdbTest
):
532 compile_args
= ("programs/infinite_loop.S", "-DMULTICORE")
534 def early_applicable(self
):
535 return len(self
.target
.harts
) > 1
539 for hart
in self
.target
.harts
:
540 self
.gdb
.select_hart(hart
)
541 self
.gdb
.p("$pc=_start")
545 for hart
in self
.target
.harts
:
546 self
.gdb
.select_hart(hart
)
549 assertIn("main", self
.gdb
.where())
550 self
.gdb
.command("delete breakpoints")
552 # Run through the entire loop.
553 for hart
in self
.target
.harts
:
554 self
.gdb
.select_hart(hart
)
555 self
.gdb
.b("main_end")
557 assertIn("main_end", self
.gdb
.where())
560 for hart
in self
.target
.harts
:
561 self
.gdb
.select_hart(hart
)
562 # Check register values.
563 hart_id
= self
.gdb
.p("$x1")
564 assertNotIn(hart_id
, hart_ids
)
565 hart_ids
.append(hart_id
)
566 for n
in range(2, 32):
567 value
= self
.gdb
.p("$x%d" % n
)
568 assertEqual(value
, hart_ids
[-1] + n
- 1)
570 # Confirmed that we read different register values for different harts.
571 # Write a new value to x1, and run through the add sequence again.
573 for hart
in self
.target
.harts
:
574 self
.gdb
.select_hart(hart
)
575 self
.gdb
.p("$x1=0x%x" % (hart
.index
* 0x800))
576 self
.gdb
.p("$pc=main_post_csrr")
578 for hart
in self
.target
.harts
:
579 self
.gdb
.select_hart(hart
)
580 assertIn("main", self
.gdb
.where())
581 # Check register values.
582 for n
in range(1, 32):
583 value
= self
.gdb
.p("$x%d" % n
)
584 assertEqual(value
, hart
.index
* 0x800 + n
- 1)
586 #class MulticoreRunHaltStepiTest(GdbTest):
587 # compile_args = ("programs/multicore.c", "-DMULTICORE")
589 # def early_applicable(self):
590 # return len(self.target.harts) > 1
594 # for hart in self.target.harts:
595 # self.gdb.select_hart(hart)
596 # self.gdb.p("$mhartid")
597 # self.gdb.p("$pc=_start")
600 # previous_hart_count = [0 for h in self.target.harts]
601 # previous_interrupt_count = [0 for h in self.target.harts]
603 # for i in range(10):
604 # # 3 attempts for each time we want the check to pass
605 # for attempt in range(3):
606 # self.gdb.global_command("echo round %d attempt %d\\n" % (i,
608 # self.gdb.c_all(wait=False)
610 # self.gdb.interrupt_all()
611 # hart_count = self.gdb.p("hart_count")
612 # interrupt_count = self.gdb.p("interrupt_count")
614 # for i, h in enumerate(self.target.harts):
615 # if hart_count[i] <= previous_hart_count[i]:
618 # if interrupt_count[i] <= previous_interrupt_count[i]:
623 # self.gdb.p("$mstatus")
624 # self.gdb.p("$priv")
625 # self.gdb.p("buf", fmt="")
626 # self.gdb.select_hart(h)
627 # pc = self.gdb.p("$pc")
629 # stepped_pc = self.gdb.p("$pc")
630 # assertNotEqual(pc, stepped_pc)
631 # previous_hart_count = hart_count
632 # previous_interrupt_count = interrupt_count
637 # "hart count or interrupt didn't increment as expected"
639 class MulticoreRunAllHaltOne(GdbTest
):
640 compile_args
= ("programs/multicore.c", "-DMULTICORE")
642 def early_applicable(self
):
643 return len(self
.target
.harts
) > 1
646 self
.gdb
.select_hart(self
.target
.harts
[0])
648 for hart
in self
.target
.harts
:
649 self
.gdb
.select_hart(hart
)
650 self
.gdb
.p("$pc=_start")
653 if not self
.gdb
.one_hart_per_gdb():
654 return 'not_applicable'
656 # Run harts in reverse order
657 for h
in reversed(self
.target
.harts
):
658 self
.gdb
.select_hart(h
)
659 self
.gdb
.c(wait
=False)
662 # Give OpenOCD time to call poll() on both harts, which is what causes
665 self
.gdb
.p("buf", fmt
="")
667 class MulticoreRtosSwitchActiveHartTest(GdbTest
):
668 compile_args
= ("programs/multicore.c", "-DMULTICORE")
670 def early_applicable(self
):
671 return len(self
.target
.harts
) > 1
674 self
.gdb
.select_hart(self
.target
.harts
[0])
676 for hart
in self
.target
.harts
:
677 self
.gdb
.select_hart(hart
)
678 self
.gdb
.p("$pc=_start")
681 if self
.gdb
.one_hart_per_gdb():
682 return 'not_applicable'
684 # Set breakpoint near '_start' label to increase the chances of a
685 # situation when all harts hit breakpoint immediately and
687 self
.gdb
.b("set_trap_handler")
689 # Check that all harts hit breakpoint one by one.
690 for _
in range(len(self
.target
.harts
)):
691 output
= self
.gdb
.c()
692 assertIn("hit Breakpoint", output
)
693 assertIn("set_trap_handler", output
)
694 assertNotIn("received signal SIGTRAP", output
)
696 class StepTest(GdbSingleHartTest
):
697 compile_args
= ("programs/step.S", )
705 main_address
= self
.gdb
.p("$pc")
706 if self
.hart
.extensionSupported("c"):
707 sequence
= (4, 8, 0xc, 0xe, 0x14, 0x18, 0x22, 0x1c, 0x24, 0x24)
709 sequence
= (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c)
710 for expected
in sequence
:
712 pc
= self
.gdb
.p("$pc")
713 assertEqual("%x" % (pc
- main_address
), "%x" % expected
)
715 class JumpHbreak(GdbSingleHartTest
):
716 """'jump' resumes execution at location. Execution stops again immediately
717 if there is a breakpoint there.
718 That second line can be trouble."""
719 compile_args
= ("programs/trigger.S", )
721 def early_applicable(self
):
722 return self
.hart
.instruction_hardware_breakpoint_count
>= 1
726 self
.gdb
.hbreak("main")
728 self
.gdb
.command("delete 1")
731 self
.gdb
.b("read_loop")
732 self
.gdb
.command("hbreak just_before_read_loop")
733 output
= self
.gdb
.command("jump just_before_read_loop")
734 assertRegexpMatches(output
, r
"Breakpoint \d, just_before_read_loop ")
735 output
= self
.gdb
.c()
736 assertRegexpMatches(output
, r
"Breakpoint \d, read_loop ")
738 class TriggerTest(GdbSingleHartTest
):
739 compile_args
= ("programs/trigger.S", )
747 output
= self
.gdb
.c()
748 assertIn("Breakpoint", output
)
749 assertIn("_exit", output
)
751 class TriggerExecuteInstant(TriggerTest
):
752 """Test an execute breakpoint on the first instruction executed out of
755 main_address
= self
.gdb
.p("$pc")
756 self
.gdb
.command("hbreak *0x%x" % (main_address
+ 4))
758 assertEqual(self
.gdb
.p("$pc"), main_address
+4)
760 # FIXME: Triggers aren't quite working yet
761 #class TriggerLoadAddress(TriggerTest):
763 # self.gdb.command("rwatch *((&data)+1)")
764 # output = self.gdb.c()
765 # assertIn("read_loop", output)
766 # assertEqual(self.gdb.p("$a0"),
767 # self.gdb.p("(&data)+1"))
770 class TriggerLoadAddressInstant(TriggerTest
):
771 """Test a load address breakpoint on the first instruction executed out of
774 self
.gdb
.command("b just_before_read_loop")
776 read_loop
= self
.gdb
.p("&read_loop")
777 read_again
= self
.gdb
.p("&read_again")
778 data
= self
.gdb
.p("&data")
779 self
.gdb
.command("rwatch *0x%x" % data
)
781 # Accept hitting the breakpoint before or after the load instruction.
782 assertIn(self
.gdb
.p("$pc"), [read_loop
, read_loop
+ 4])
783 assertEqual(self
.gdb
.p("$a0"), self
.gdb
.p("&data"))
786 assertIn(self
.gdb
.p("$pc"), [read_again
, read_again
+ 4])
787 assertEqual(self
.gdb
.p("$a0"), self
.gdb
.p("&data"))
789 # FIXME: Triggers aren't quite working yet
790 #class TriggerStoreAddress(TriggerTest):
792 # self.gdb.command("watch *((&data)+3)")
793 # output = self.gdb.c()
794 # assertIn("write_loop", output)
795 # assertEqual(self.gdb.p("$a0"),
796 # self.gdb.p("(&data)+3"))
799 class TriggerStoreAddressInstant(TriggerTest
):
801 """Test a store address breakpoint on the first instruction executed out
803 self
.gdb
.command("b just_before_write_loop")
805 write_loop
= self
.gdb
.p("&write_loop")
806 data
= self
.gdb
.p("&data")
807 self
.gdb
.command("watch *0x%x" % data
)
808 output
= self
.gdb
.c()
809 if "_exit (status=0)" in output
:
810 # We ran to _exit. It looks as if we didn't hit the trigger at all.
811 # However this can be "correct" behavior. gdb's definition of
812 # "watch" is to run until the value in memory changes. To do this
813 # it reads the memory value when the trigger is set, and then when
814 # the halt happens. Because our triggers can fire just before the
815 # write happens, when gdb does this check the memory hasn't
816 # changed. So it silently resumes running.
817 # https://github.com/riscv/riscv-openocd/issues/295 tracks this
818 # problem. Until it's fixed, we're going to allow running to _exit.
821 # Accept hitting the breakpoint before or after the store instruction.
822 assertIn(self
.gdb
.p("$pc"), [write_loop
, write_loop
+ 4])
823 assertEqual(self
.gdb
.p("$a0"), self
.gdb
.p("&data"))
825 class TriggerDmode(TriggerTest
):
826 def early_applicable(self
):
827 return self
.hart
.honors_tdata1_hmode
829 def check_triggers(self
, tdata1_lsbs
, tdata2
):
830 dmode
= 1 << (self
.hart
.xlen
-5)
834 if self
.hart
.xlen
== 32:
836 elif self
.hart
.xlen
== 64:
837 xlen_type
= 'long long'
839 raise NotImplementedError
844 tdata1
= self
.gdb
.p("((%s *)&data)[%d]" % (xlen_type
, 2*i
))
847 tdata2
= self
.gdb
.p("((%s *)&data)[%d]" % (xlen_type
, 2*i
+1))
852 assertEqual(tdata1
& 0xffff, tdata1_lsbs
)
853 assertEqual(tdata2
, tdata2
)
856 assertEqual(dmode_count
, 1)
861 self
.gdb
.command("hbreak write_load_trigger")
862 self
.gdb
.b("clear_triggers")
863 self
.gdb
.p("$pc=write_store_trigger")
864 output
= self
.gdb
.c()
865 assertIn("write_load_trigger", output
)
866 self
.check_triggers((1<<6) |
(1<<1), 0xdeadbee0)
867 output
= self
.gdb
.c()
868 assertIn("clear_triggers", output
)
869 self
.check_triggers((1<<6) |
(1<<0), 0xfeedac00)
871 class RegsTest(GdbSingleHartTest
):
872 compile_args
= ("programs/regs.S", )
876 self
.gdb
.b("handle_trap")
879 class WriteGprs(RegsTest
):
881 regs
= [("x%d" % n
) for n
in range(2, 32)]
883 self
.gdb
.p("$pc=write_regs")
884 for i
, r
in enumerate(regs
):
885 self
.gdb
.p("$%s=%d" % (r
, (0xdeadbeef<<i
)+17))
886 self
.gdb
.p("$x1=data")
887 self
.gdb
.command("b all_done")
888 output
= self
.gdb
.c()
889 assertIn("Breakpoint ", output
)
891 # Just to get this data in the log.
892 self
.gdb
.command("x/30gx data")
893 self
.gdb
.command("info registers")
894 for n
in range(len(regs
)):
895 assertEqual(self
.gdb
.x("data+%d" % (8*n
), 'g'),
896 ((0xdeadbeef<<n
)+17) & ((1<<self
.hart
.xlen
)-1))
898 class WriteCsrs(RegsTest
):
900 # As much a test of gdb as of the simulator.
901 self
.gdb
.p("$mscratch=0")
903 assertEqual(self
.gdb
.p("$mscratch"), 0)
904 self
.gdb
.p("$mscratch=123")
906 assertEqual(self
.gdb
.p("$mscratch"), 123)
908 self
.gdb
.p("$pc=write_regs")
909 self
.gdb
.p("$x1=data")
910 self
.gdb
.command("b all_done")
911 self
.gdb
.command("c")
913 assertEqual(123, self
.gdb
.p("$mscratch"))
914 assertEqual(123, self
.gdb
.p("$x1"))
915 assertEqual(123, self
.gdb
.p("$csr832"))
917 class DownloadTest(GdbTest
):
919 # pylint: disable=attribute-defined-outside-init
920 length
= min(2**10, self
.hart
.ram_size
- 2048)
921 self
.download_c
= tempfile
.NamedTemporaryFile(prefix
="download_",
922 suffix
=".c", delete
=False)
923 self
.download_c
.write("#include <stdint.h>\n")
924 self
.download_c
.write(
925 "unsigned int crc32a(uint8_t *message, unsigned int size);\n")
926 self
.download_c
.write("uint32_t length = %d;\n" % length
)
927 self
.download_c
.write("uint8_t d[%d] = {\n" % length
)
929 assert length
% 16 == 0
930 for i
in range(length
/ 16):
931 self
.download_c
.write(" /* 0x%04x */ " % (i
* 16))
933 value
= random
.randrange(1<<8)
934 self
.download_c
.write("0x%02x, " % value
)
935 self
.crc
= binascii
.crc32("%c" % value
, self
.crc
)
936 self
.download_c
.write("\n")
937 self
.download_c
.write("};\n")
938 self
.download_c
.write("uint8_t *data = &d[0];\n")
939 self
.download_c
.write(
940 "uint32_t main() { return crc32a(data, length); }\n")
941 self
.download_c
.flush()
946 self
.binary
= self
.target
.compile(self
.hart
, self
.download_c
.name
,
947 "programs/checksum.c")
948 self
.gdb
.global_command("file %s" % self
.binary
)
952 self
.parkOtherHarts()
953 self
.gdb
.command("b _exit")
955 assertEqual(self
.gdb
.p("status"), self
.crc
)
956 os
.unlink(self
.download_c
.name
)
958 #class MprvTest(GdbSingleHartTest):
959 # compile_args = ("programs/mprv.S", )
964 # """Test that the debugger can access memory when MPRV is set."""
965 # self.gdb.c(wait=False)
967 # self.gdb.interrupt()
968 # output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)")
969 # assertIn("0xbead", output)
971 class PrivTest(GdbSingleHartTest
):
972 compile_args
= ("programs/priv.S", )
974 # pylint: disable=attribute-defined-outside-init
977 misa
= self
.hart
.misa
978 self
.supported
= set()
980 self
.supported
.add(0)
982 self
.supported
.add(1)
984 self
.supported
.add(2)
985 self
.supported
.add(3)
987 class PrivRw(PrivTest
):
989 """Test reading/writing priv."""
990 # Disable physical memory protection by allowing U mode access to all
993 self
.gdb
.p("$pmpcfg0=0xf") # TOR, R, W, X
994 self
.gdb
.p("$pmpaddr0=0x%x" %
995 ((self
.hart
.ram
+ self
.hart
.ram_size
) >> 2))
996 except testlib
.CouldNotFetch
:
997 # PMP registers are optional
1000 # Ensure Virtual Memory is disabled if applicable (SATP register is not
1003 self
.gdb
.p("$satp=0")
1004 except testlib
.CouldNotFetch
:
1005 # SATP only exists if you have S mode.
1008 # Leave the PC at _start, where the first 4 instructions should be
1009 # legal in any mode.
1010 for privilege
in range(4):
1011 self
.gdb
.p("$priv=%d" % privilege
)
1013 actual
= self
.gdb
.p("$priv")
1014 assertIn(actual
, self
.supported
)
1015 if privilege
in self
.supported
:
1016 assertEqual(actual
, privilege
)
1018 # XXX temporarily disabling this test
1019 #class PrivChange(PrivTest):
1021 # """Test that the core's privilege level actually changes."""
1023 # if 0 not in self.supported:
1024 # return 'not_applicable'
1026 # self.gdb.b("main")
1030 # self.gdb.p("$priv=3")
1031 # main_address = self.gdb.p("$pc")
1033 # assertEqual("%x" % self.gdb.p("$pc"), "%x" % (main_address+4))
1036 # self.gdb.p("$priv=0")
1038 # # Should have taken an exception, so be nowhere near main.
1039 # pc = self.gdb.p("$pc")
1040 # assertTrue(pc < main_address or pc > main_address + 0x100)
1044 parser
= argparse
.ArgumentParser(
1045 description
="Test that gdb can talk to a RISC-V target.",
1047 Example command line from the real world:
1048 Run all RegsTest cases against a physical FPGA, with custom openocd command:
1049 ./gdbserver.py --freedom-e300 --server_cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" Simple
1051 targets
.add_target_options(parser
)
1053 testlib
.add_test_run_options(parser
)
1055 # TODO: remove global
1056 global parsed
# pylint: disable=global-statement
1057 parsed
= parser
.parse_args()
1058 target
= targets
.target(parsed
)
1059 testlib
.print_log_names
= parsed
.print_log_names
1061 module
= sys
.modules
[__name__
]
1063 return testlib
.run_all_tests(module
, target
, parsed
)
1065 # TROUBLESHOOTING TIPS
1066 # If a particular test fails, run just that one test, eg.:
1067 # ./gdbserver.py MprvTest.test_mprv
1068 # Then inspect gdb.log and spike.log to see what happened in more detail.
1070 if __name__
== '__main__':