diff options
-rwxr-xr-x | debug/gdbserver.py | 100 | ||||
-rw-r--r-- | debug/testlib.py | 4 |
2 files changed, 80 insertions, 24 deletions
diff --git a/debug/gdbserver.py b/debug/gdbserver.py index 1280878..1a74a95 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -66,6 +66,20 @@ def srec_parse(line): if typ == b'S0': # header return 0, 0, 0 + elif typ == b'S1': + # data with 16-bit address + address = int(line[4:8], 16) + for i in range(4, count+1): + data += f"{int(line[2 * i:2 * i + 2], 16):c}" + # Ignore the checksum. + return 1, address, data + elif typ == b'S2': + # data with 24-bit address + address = int(line[4:10], 16) + for i in range(5, count+1): + data += f"{int(line[2 * i:2 * i + 2], 16):c}" + # Ignore the checksum. + return 2, address, data elif typ == b'S3': # data with 32-bit address # Any higher bits were chopped off. @@ -74,9 +88,9 @@ def srec_parse(line): data += f"{int(line[2 * i:2 * i + 2], 16):c}" # Ignore the checksum. return 3, address, data - elif typ == b'S7': + elif typ in (b'S7', b'S8', b'S9'): # ignore execution start field - return 7, 0, 0 + return int(typ[-1]), 0, 0 else: raise TestFailed(f"Unsupported SREC type {typ!r}.") @@ -389,7 +403,7 @@ class MemTestBlock(GdbTest): highest_seen = 0 for line in b: record_type, address, line_data = srec_parse(line) - if record_type == 3: + if record_type in (1, 2, 3): offset = address - (self.hart.ram & 0xffffffff) written_data = data[offset:offset+len(line_data)] highest_seen += len(line_data) @@ -676,6 +690,47 @@ class HwbpManual(DebugTest): return self.target.support_manual_hwbp and \ self.hart.instruction_hardware_breakpoint_count >= 1 + # TODO: This can be removed once + # https://github.com/riscv-collab/riscv-openocd/pull/1111 + # is merged. + def check_reserve_trigger_support(self): + not_supp_msg = "RESERVE_TRIGGER_NOT_SUPPORTED" + if not_supp_msg in self.gdb.command( + "monitor if [catch {riscv reserve_trigger 0 on} e] {echo " + + not_supp_msg + "}").splitlines(): + raise TestNotApplicable + + def set_manual_trigger(self, tdata1, tdata2): + for tselect in itertools.count(0): + self.gdb.p(f"$tselect={tselect}") + if self.gdb.p("$tselect") != tselect: + raise TestNotApplicable + + self.gdb.command( + f"monitor riscv reserve_trigger {tselect} on") + + # Need to disable the trigger before writing tdata2 + self.gdb.p("$tdata1=0") + # Need to write a valid value to tdata2 before writing tdata1 + self.gdb.p(f"$tdata2=0x{tdata2:x}") + self.gdb.p(f"$tdata1=0x{tdata1:x}") + + tdata2_rb = self.gdb.p("$tdata2") + tdata1_rb = self.gdb.p("$tdata1") + if tdata1_rb == tdata1 and tdata2_rb == tdata2: + return tselect + + type_rb = tdata1_rb & MCONTROL_TYPE(self.hart.xlen) + type_none = set_field(0, MCONTROL_TYPE(self.hart.xlen), + MCONTROL_TYPE_NONE) + if type_rb == type_none: + raise TestNotApplicable + + self.gdb.p("$tdata1=0") + self.gdb.command( + f"monitor riscv reserve_trigger {tselect} off") + assert False + def test(self): if not self.hart.honors_tdata1_hmode: # Run to main before setting the breakpoint, because startup code @@ -684,6 +739,12 @@ class HwbpManual(DebugTest): self.gdb.c() self.gdb.command("delete") + + # TODO: This can be removed once + # https://github.com/riscv-collab/riscv-openocd/pull/1111 + # is merged. + self.check_reserve_trigger_support() + #self.gdb.hbreak("rot13") tdata1 = MCONTROL_DMODE(self.hart.xlen) tdata1 = set_field(tdata1, MCONTROL_TYPE(self.hart.xlen), @@ -692,26 +753,9 @@ class HwbpManual(DebugTest): tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL) tdata1 |= MCONTROL_M | MCONTROL_S | MCONTROL_U | MCONTROL_EXECUTE - tselect = 0 - while True: - self.gdb.p(f"$tselect={tselect}") - value = self.gdb.p("$tselect") - if value != tselect: - raise TestNotApplicable - # Need to disable the trigger before writing tdata2 - self.gdb.p("$tdata1=0") - # Need to write a valid value to tdata2 before writing tdata1 - self.gdb.p("$tdata2=&rot13") - self.gdb.p(f"$tdata1=0x{tdata1:x}") - value = self.gdb.p("$tdata1") - if value == tdata1: - break - if value & MCONTROL_TYPE(self.hart.xlen) == MCONTROL_TYPE_NONE: - raise TestNotApplicable - self.gdb.p("$tdata1=0") - tselect += 1 + tdata2 = self.gdb.p("&rot13") - self.gdb.command(f"monitor riscv reserve_trigger {tselect} on") + tselect = self.set_manual_trigger(tdata1, tdata2) # The breakpoint should be hit exactly 2 times. for _ in range(2): @@ -728,14 +772,22 @@ class HwbpManual(DebugTest): self.gdb.c() before = self.gdb.p("$pc") assertEqual(before, self.gdb.p("&crc32a")) + self.gdb.stepi() - after = self.gdb.p("$pc") - assertNotEqual(before, after) + assertEqual(before, self.gdb.p("$pc"), + "OpenOCD shouldn't disable a reserved trigger.") # Remove the manual HW breakpoint. assertEqual(tselect, self.gdb.p("$tselect")) self.gdb.p("$tdata1=0") + self.gdb.stepi() + assertNotEqual(before, self.gdb.p("$pc"), + "OpenOCD should be able to step from a removed BP.") + + self.gdb.command( + f"monitor riscv reserve_trigger {tselect} off") + self.gdb.b("_exit") self.exit() diff --git a/debug/testlib.py b/debug/testlib.py index 0279b08..cf62863 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -65,6 +65,7 @@ def compile(args): # pylint: disable=redefined-builtin class Spike: # pylint: disable=too-many-instance-attributes # pylint: disable=too-many-locals + # pylint: disable=too-many-positional-arguments def __init__(self, target, halted=False, timeout=None, with_jtag_gdb=True, isa=None, progbufsize=None, dmi_rti=None, abstract_rti=None, support_hasel=True, support_abstract_csr=True, @@ -300,6 +301,8 @@ class VcsSim: class Openocd: # pylint: disable=too-many-instance-attributes # pylint: disable-next=consider-using-with + # pylint: disable=too-many-positional-arguments + # pylint: disable=consider-using-with logfile = tempfile.NamedTemporaryFile(prefix='openocd', suffix='.log') logname = logfile.name @@ -717,6 +720,7 @@ class Gdb: 11, 149, 107, 163, 73, 47, 43, 173, 7, 109, 101, 103, 191, 2, 139, 97, 193, 157, 3, 29, 79, 113, 5, 89, 19, 37, 71, 179, 59, 137, 53) + # pylint: disable=too-many-positional-arguments def __init__(self, target, ports, cmd=None, timeout=60, binaries=None, logremote=False): assert ports |