From 300c38d335ed1f323ef7f4fd4cb9c27faf2a75a8 Mon Sep 17 00:00:00 2001 From: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> Date: Sun, 19 Oct 2025 11:43:49 +0900 Subject: [PATCH 1/9] debug: test S and U are supported for tdata1 Set MCONTROL_S and/or MCONTROL_U bits only if the hart supports S-mode and/or U-mode. Signed-off-by: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> --- debug/gdbserver.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/debug/gdbserver.py b/debug/gdbserver.py index 92f7ce33f..2e83c75f5 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -758,7 +758,11 @@ def test(self): MCONTROL_TYPE_MATCH) tdata1 = set_field(tdata1, MCONTROL_ACTION, MCONTROL_ACTION_DEBUG_MODE) tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL) - tdata1 |= MCONTROL_M | MCONTROL_S | MCONTROL_U | MCONTROL_EXECUTE + tdata1 |= MCONTROL_M | MCONTROL_EXECUTE + if self.hart.extensionSupported("S"): + tdata1 |= MCONTROL_S + if self.hart.extensionSupported("U"): + tdata1 |= MCONTROL_U tdata2 = self.gdb.p("&rot13") From d55e525d473e989b15540d9ef9625d29ab503c4f Mon Sep 17 00:00:00 2001 From: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> Date: Sun, 19 Oct 2025 12:29:26 +0900 Subject: [PATCH 2/9] debug: test S is supported in TranslateTest TranslateTest depends on the S extension being supported. Without this change, the test fails on targets that do not support S extension. Signed-off-by: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> --- debug/gdbserver.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debug/gdbserver.py b/debug/gdbserver.py index 2e83c75f5..d06acb9ec 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -1721,7 +1721,8 @@ class TranslateTest(GdbSingleHartTest): compile_args = ("programs/translate.c", ) def early_applicable(self): - return self.hart.ram_size >= 32 * 1024 + return self.hart.ram_size >= 32 * 1024 and \ + self.hart.extensionSupported("S") def setup(self): self.disable_pmp() From 68257fb59c4a96a4043de39e6ee0b0e9a7cec168 Mon Sep 17 00:00:00 2001 From: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> Date: Sun, 19 Oct 2025 11:46:35 +0900 Subject: [PATCH 3/9] debug: test implements_page_virtual_memory before executing sfence.vma instruction cf. #537 Signed-off-by: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> --- debug/testlib.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/debug/testlib.py b/debug/testlib.py index 82fe3fb61..17f1541da 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -1492,14 +1492,16 @@ def set_pmp_deny(self, address, size=4 * 1024): self.gdb.p("$pmpcfg0=0x98") # L, NAPOT, !R, !W, !X self.gdb.p("$pmpaddr0=" f"0x{((address >> 2) | ((size - 1) >> 3)):x}") - # PMP changes require an sfence.vma, 0x12000073 is sfence.vma - self.gdb.command("monitor riscv exec_progbuf 0x12000073") + if self.target.implements_page_virtual_memory: + # PMP changes require an sfence.vma, 0x12000073 is sfence.vma + self.gdb.command("monitor riscv exec_progbuf 0x12000073") def reset_pmp_deny(self): self.gdb.p("$pmpcfg0=0") self.gdb.p("$pmpaddr0=0") - # PMP changes require an sfence.vma, 0x12000073 is sfence.vma - self.gdb.command("monitor riscv exec_progbuf 0x12000073") + if self.target.implements_page_virtual_memory: + # PMP changes require an sfence.vma, 0x12000073 is sfence.vma + self.gdb.command("monitor riscv exec_progbuf 0x12000073") def disable_pmp(self): # Disable physical memory protection by allowing U mode access to all From f355fc34e1e6297d5e8f54dcbb4ac5beb6275de8 Mon Sep 17 00:00:00 2001 From: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> Date: Mon, 27 Oct 2025 22:51:00 +0900 Subject: [PATCH 4/9] debug: set size arguments of set_pmp_deny() to 8 The default size argument of set_pmp_deny() is 4KB. However, bad_address in spike32.py and spike64.py assumes that the size is less than or equal to 8 bytes. 8 bytes is enough for each test calling set_pmp_deny(). So, set the size argument of set_pmp_deny() to 8 explicitly. Signed-off-by: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> --- debug/gdbserver.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug/gdbserver.py b/debug/gdbserver.py index d06acb9ec..187e4dd45 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -279,7 +279,7 @@ class MemTestReadInvalid(SimpleMemoryTest): def test(self): bad_address = self.hart.bad_address if self.target.support_set_pmp_deny: - self.set_pmp_deny(bad_address) + self.set_pmp_deny(bad_address, 8) self.gdb.command("monitor riscv set_mem_access progbuf abstract") good_address = self.hart.ram + 0x80 @@ -2195,7 +2195,7 @@ def test(self): # Use NULL if a known-bad address is not provided. bad_address = self.hart.bad_address or 0 if self.target.support_set_pmp_deny: - self.set_pmp_deny(bad_address) + self.set_pmp_deny(bad_address, 8) self.gdb.command("monitor riscv set_mem_access progbuf abstract") self.gdb.p(f"fox=(char*)0x{bad_address:08x}") output = self.gdb.c() From ccda9c9cc6d6c3b4466218cd0e0e335c6ef7d495 Mon Sep 17 00:00:00 2001 From: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> Date: Sun, 19 Oct 2025 12:36:11 +0900 Subject: [PATCH 5/9] debug: rename honors_tdata1_hmode to honors_tdata1_dmode This is for the dmode bit in tdata1. Signed-off-by: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> --- debug/gdbserver.py | 6 +++--- debug/targets.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/debug/gdbserver.py b/debug/gdbserver.py index 187e4dd45..f6c97db8a 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -634,7 +634,7 @@ def early_applicable(self): return self.hart.instruction_hardware_breakpoint_count > 0 def test(self): - if not self.hart.honors_tdata1_hmode: + if not self.hart.honors_tdata1_dmode: # Run to main before setting the breakpoint, because startup code # will otherwise clear the trigger that we set. self.gdb.b("main") @@ -739,7 +739,7 @@ def set_manual_trigger(self, tdata1, tdata2): assert False def test(self): - if not self.hart.honors_tdata1_hmode: + if not self.hart.honors_tdata1_dmode: # Run to main before setting the breakpoint, because startup code # will otherwise clear the trigger that we set. self.gdb.b("main") @@ -1474,7 +1474,7 @@ def test(self): class TriggerDmode(TriggerTest): def early_applicable(self): - return self.hart.honors_tdata1_hmode and \ + return self.hart.honors_tdata1_dmode and \ self.hart.instruction_hardware_breakpoint_count > 0 def check_triggers(self, tdata1_lsbs, tdata2): diff --git a/debug/targets.py b/debug/targets.py index eca02313f..5785118e7 100644 --- a/debug/targets.py +++ b/debug/targets.py @@ -23,7 +23,7 @@ class Hart: # this value set to False are not compliant with the spec (but still usable # as long as running code doesn't try to mess with triggers set by an # external debugger). - honors_tdata1_hmode = True + honors_tdata1_dmode = True # Address where a r/w/x block of RAM starts, together with its size. ram = None From fa134642b26c10c3c6b8be036ddf3507dc7de690 Mon Sep 17 00:00:00 2001 From: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> Date: Sun, 19 Oct 2025 12:12:40 +0900 Subject: [PATCH 6/9] debug: fixed obsoleted openocd-command names This suppresses warnings like: Warning: Command 'gdb_port' is deprecated, please use 'gdb port' instead. Warning: Command 'tcl_port' is deprecated, please use 'tcl port' instead. Warning: Command 'telnet_port' is deprecated, please use 'telnet port' instead. from debug/README.md: > openocd ..., which should be the latest from https://github.com/riscv/riscv-openocd.git. Signed-off-by: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> --- debug/testlib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debug/testlib.py b/debug/testlib.py index 17f1541da..8286fe40f 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -321,11 +321,11 @@ def __init__(self, server_cmd=None, config=None, debug=False, timeout=60, # line, since they are executed in order. cmd += [ # Tell OpenOCD to bind gdb to an unused, ephemeral port. - "--command", "gdb_port 0", + "--command", "gdb port 0", # We create a socket for OpenOCD command line (TCL-RPC) - "--command", "tcl_port 0", + "--command", "tcl port 0", # don't use telnet - "--command", "telnet_port disabled", + "--command", "telnet port disabled", ] if config: From 9e92de63f5b4d6a178362c511bd918bcf639ed09 Mon Sep 17 00:00:00 2001 From: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> Date: Sun, 19 Oct 2025 12:15:14 +0900 Subject: [PATCH 7/9] debug: not to throw exception on an expected error This change makes debug/testlib.py not throw an exception when an expected error occurs while creating the logs/ directory. Fixing this is useful when debugging with python debugger not to break at the exception every time. Signed-off-by: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> --- debug/testlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug/testlib.py b/debug/testlib.py index 8286fe40f..f11bbe899 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -1137,7 +1137,7 @@ def run_all_tests(module, target, parsed): return 0 try: - os.makedirs(parsed.logs) + os.makedirs(parsed.logs, exist_ok=True) except OSError: # There's a race where multiple instances of the test program might # decide to create the logs directory at the same time. From 0488fae40396fc3a55eaa912fb963ca07cc1042f Mon Sep 17 00:00:00 2001 From: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> Date: Sun, 19 Oct 2025 11:49:36 +0900 Subject: [PATCH 8/9] debug: call create() instead of target() U500Sim.py is the only example of a target that uses VcsSim class. It does not work without this fix. Signed-off-by: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> --- debug/targets/SiFive/Freedom/U500Sim.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug/targets/SiFive/Freedom/U500Sim.py b/debug/targets/SiFive/Freedom/U500Sim.py index 065ab08ae..8abbc1ab7 100644 --- a/debug/targets/SiFive/Freedom/U500Sim.py +++ b/debug/targets/SiFive/Freedom/U500Sim.py @@ -13,5 +13,5 @@ class U500Sim(targets.Target): openocd_config_path = "Freedom.cfg" harts = [U500Hart()] - def target(self): + def create(self): return testlib.VcsSim(sim_cmd=self.sim_cmd, debug=False) From dd719cdd4258cd106fa0a4bee055cfd9688654a2 Mon Sep 17 00:00:00 2001 From: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> Date: Sat, 1 Nov 2025 01:42:24 +0900 Subject: [PATCH 9/9] debug: VcsSim: make server start string configurable example: for https://github.com/fjullien/jtag_vpi/blob/master/jtag_common.c#L80 def create(self): return testlib.VcsSim(..., server_stared="^Starting jtag_vpi server:.*, port (\d+)/tcp") Signed-off-by: Hiroo HAYASHI <24754036+hirooih@users.noreply.github.com> --- debug/testlib.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/debug/testlib.py b/debug/testlib.py index f11bbe899..7503fd7e9 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -247,7 +247,8 @@ class VcsSim: logname = logfile.name lognames = [logname] - def __init__(self, sim_cmd=None, debug=False, timeout=300): + def __init__(self, sim_cmd=None, debug=False, timeout=300, + server_started=r"^Listening on port (\d+)$"): if sim_cmd: cmd = shlex.split(sim_cmd) else: @@ -281,7 +282,7 @@ def __init__(self, sim_cmd=None, debug=False, timeout=300): line = listenfile.readline() if not line: time.sleep(1) - match = re.match(r"^Listening on port (\d+)$", line) + match = re.match(server_started, line) if match: done = True self.port = int(match.group(1))