mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
feat: add management debug reset and JTAG integration for Hazard3
- Implemented module to handle debug reset requests, ensuring proper synchronization with the AHB-Lite bridge. - Created to integrate JTAG-DTM and Debug Module, facilitating abstract command exposure. - Updated and modules to include JTAG interface signals. - Enhanced the development environment with scripts for running debug sessions using OpenOCD and GDB. - Added tests for management debug reset functionality and JTAG integration, ensuring correct behavior under various scenarios. - Updated SDC generation to include JTAG clock domain and port requirements. - Modified various scripts to support new debug features and ensure compatibility with the Hazard3 architecture.
This commit is contained in:
55 files changed
+1544
-227
No files matched your search
@@ -0,0 +1,73 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module mgmt_debug_reset_tb;
|
||||
logic s_clk;
|
||||
logic s_rst_n;
|
||||
logic s_reset_req;
|
||||
logic s_bridge_idle;
|
||||
logic s_core_rst_n;
|
||||
logic s_reset_done;
|
||||
|
||||
always #5 s_clk = ~s_clk;
|
||||
|
||||
mgmt_debug_reset u_mgmt_debug_reset (
|
||||
.clk_i (s_clk),
|
||||
.rst_n_i (s_rst_n),
|
||||
.reset_req_i (s_reset_req),
|
||||
.bridge_idle_i(s_bridge_idle),
|
||||
.core_rst_n_o (s_core_rst_n),
|
||||
.reset_done_o (s_reset_done)
|
||||
);
|
||||
|
||||
initial begin
|
||||
s_clk = 1'b0;
|
||||
s_rst_n = 1'b0;
|
||||
s_reset_req = 1'b0;
|
||||
s_bridge_idle = 1'b1;
|
||||
|
||||
repeat (2) @(posedge s_clk);
|
||||
s_rst_n = 1'b1;
|
||||
repeat (4) @(posedge s_clk);
|
||||
#1;
|
||||
assert (s_core_rst_n && s_reset_done)
|
||||
else $fatal(1, "initial reset release failed");
|
||||
|
||||
s_bridge_idle = 1'b0;
|
||||
s_reset_req = 1'b1;
|
||||
@(posedge s_clk);
|
||||
s_reset_req = 1'b0;
|
||||
repeat (2) @(posedge s_clk);
|
||||
#1;
|
||||
assert (s_core_rst_n && !s_reset_done)
|
||||
else $fatal(1, "request did not wait for idle");
|
||||
|
||||
s_bridge_idle = 1'b1;
|
||||
@(posedge s_clk);
|
||||
#1;
|
||||
assert (!s_core_rst_n && !s_reset_done)
|
||||
else $fatal(1, "core reset did not assert");
|
||||
repeat (4) @(posedge s_clk);
|
||||
#1;
|
||||
assert (s_core_rst_n && s_reset_done)
|
||||
else $fatal(1, "core reset did not release");
|
||||
|
||||
s_reset_req = 1'b1;
|
||||
repeat (2) @(posedge s_clk);
|
||||
#1;
|
||||
assert (!s_core_rst_n && !s_reset_done)
|
||||
else $fatal(1, "held reset did not assert");
|
||||
repeat (3) @(posedge s_clk);
|
||||
#1;
|
||||
assert (!s_core_rst_n && !s_reset_done)
|
||||
else $fatal(1, "held reset released too early");
|
||||
|
||||
s_reset_req = 1'b0;
|
||||
repeat (4) @(posedge s_clk);
|
||||
#1;
|
||||
assert (s_core_rst_n && s_reset_done)
|
||||
else $fatal(1, "held reset did not release");
|
||||
|
||||
$display("management debug reset test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -36,8 +36,13 @@ def test_clock_reset_domain_inventory_matches_the_rcu() -> None:
|
||||
"external",
|
||||
"system",
|
||||
"audio",
|
||||
"jtag",
|
||||
"dvp",
|
||||
}
|
||||
assert {
|
||||
(crossing["name"], crossing["source"], crossing["destination"])
|
||||
for crossing in document["crossings"]
|
||||
} >= {("jtag_dmi", "jtag", "system")}
|
||||
|
||||
|
||||
def test_clock_reset_domain_inventory_rejects_unknown_domain_and_instance(tmp_path: Path) -> None:
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
"""Directed reset-sequencing test for the management Hazard3 debug path."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_management_debug_reset_waits_for_the_ahbl_bridge(tmp_path: Path) -> None:
|
||||
iverilog = shutil.which("iverilog")
|
||||
vvp = shutil.which("vvp")
|
||||
if iverilog is None or vvp is None:
|
||||
return
|
||||
|
||||
simulation = tmp_path / "mgmt_debug_reset_tb"
|
||||
sources = (
|
||||
ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv",
|
||||
ROOT / "rtl/managed/clusterip/common/rtl/clkrst/rst_sync.sv",
|
||||
ROOT / "rtl/mini/top/mgmt_debug_reset.sv",
|
||||
ROOT / "tests/rtl/mgmt_debug_reset_tb.sv",
|
||||
)
|
||||
subprocess.run(
|
||||
[
|
||||
iverilog,
|
||||
"-g2012",
|
||||
"-DSV_ASSRT_DISABLE",
|
||||
f"-I{ROOT / 'rtl/managed/clusterip/common/rtl'}",
|
||||
"-s",
|
||||
"mgmt_debug_reset_tb",
|
||||
"-o",
|
||||
str(simulation),
|
||||
*(str(source) for source in sources),
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
||||
|
||||
assert "management debug reset test passed" in result.stdout
|
||||
@@ -57,6 +57,9 @@ def test_pin_map_generates_asic_and_platform_bindings(tmp_path: Path) -> None:
|
||||
assert "inout extclk_i_pad," in ports
|
||||
assert "input xi_i_pad," in ports
|
||||
assert "inout sdram_dq15_io_pad" in ports
|
||||
assert "inout jtag_tck_i_pad" in ports
|
||||
assert "inout jtag_trst_n_i_pad" in ports
|
||||
assert "output jtag_tdo_o_pad" in ports
|
||||
assert "u_gpio_31_io_pad" in pads
|
||||
assert "u_sdram_dq15_io_pad" in pads
|
||||
assert ".gpio_30_io_pad(gpio_io30)" in fpga
|
||||
@@ -65,6 +68,9 @@ def test_pin_map_generates_asic_and_platform_bindings(tmp_path: Path) -> None:
|
||||
assert testbench.count(".gpio_24_io_pad(") == 1
|
||||
assert ".sdram_clk_o_pad(s_sdram_clk)" in verilator
|
||||
assert ".sdram_dq15_io_pad(s_sdram_dq[15])" in verilator
|
||||
assert ".jtag_tck_i_pad(s_jtag_tck)" in verilator
|
||||
assert ".jtag_tdo_o_pad(s_jtag_tdo)" in verilator
|
||||
assert ".jtag_tck_i_pad(s_jtag_tck)" in testbench
|
||||
assert "user_gpio_" not in ports
|
||||
assert "user_gpio_" not in pads
|
||||
assert "user_gpio_" not in testbench
|
||||
|
||||
@@ -129,6 +129,21 @@ def test_generate_all_is_stable_and_expands_paths(tmp_path: Path) -> None:
|
||||
}.issubset({path.name for path in generated})
|
||||
|
||||
|
||||
def test_filelist_round_trips_verilog_define_values(tmp_path: Path) -> None:
|
||||
generate_all(tmp_path, ["+define+SOC_JTAG_IDCODE=32'hDEADBEEF"])
|
||||
|
||||
assert (tmp_path / "def.fl").read_text(encoding="utf-8") == (
|
||||
"+define+SOC_JTAG_IDCODE=32'hDEADBEEF\n"
|
||||
)
|
||||
parsed = parse_filelists([tmp_path / "def.fl"])
|
||||
output = tmp_path / "round-trip.fl"
|
||||
write_filelist(output, parsed)
|
||||
assert output.read_text(encoding="utf-8") == (
|
||||
"+define+SOC_JTAG_IDCODE=32'hDEADBEEF\n"
|
||||
)
|
||||
assert parse_filelists([output]) == parsed
|
||||
|
||||
|
||||
def test_source_export_selects_the_requested_management_core(tmp_path: Path) -> None:
|
||||
module_path = ROOT / "syn/tools/export_soc_sources.py"
|
||||
spec = importlib.util.spec_from_file_location("retrosoc_source_export", module_path)
|
||||
@@ -153,6 +168,8 @@ def test_source_export_selects_the_requested_management_core(tmp_path: Path) ->
|
||||
have_sram_if=False,
|
||||
have_sram_macro=False,
|
||||
have_sva=False,
|
||||
have_debug="YES" if core == "HAZARD3" else "NO",
|
||||
jtag_idcode="DEADBEEF",
|
||||
dynamic_core_filelist=dynamic_core,
|
||||
dynamic_ip_filelist=dynamic_ip,
|
||||
)
|
||||
@@ -167,6 +184,8 @@ def test_source_export_selects_the_requested_management_core(tmp_path: Path) ->
|
||||
)
|
||||
|
||||
assert f"+define+CORE_{core}" in filelist.defines
|
||||
assert "+define+SOC_JTAG_IDCODE=-559038737" in filelist.defines
|
||||
assert ("+define+HAVE_DEBUG" in filelist.defines) == (core == "HAZARD3")
|
||||
assert any(path.name == source_name for path in filelist.files)
|
||||
|
||||
|
||||
@@ -605,6 +624,7 @@ def test_development_environment_contract_is_lock_pinned(tmp_path: Path) -> None
|
||||
stamp = stamp_data(ROOT, cache, DEFAULT_TOOLS, lock, lock_path)
|
||||
|
||||
assert stamp["tools"]["verilator"] == lock["toolchains"]["ubuntu-22.04"]["verilator"]["version"]
|
||||
assert stamp["tools"]["openocd"] == lock["toolchains"]["ubuntu-22.04"]["openocd"]["version"]
|
||||
assert set(stamp["python_requirements"]) == {"requirements/build.txt", "requirements/ci.txt"}
|
||||
activation = render_activation(cache, [cache / "venv/bin", cache / "toolchains/verilator/bin"])
|
||||
assert "export RETROSOC_DEVELOPMENT_CACHE=" in activation
|
||||
@@ -673,6 +693,35 @@ def test_management_core_selection_is_limited_to_hazard3_and_picorv32() -> None:
|
||||
assert ".RESET_VECTOR (`SOC_CPU_RESET_ADDR)" in wrapper
|
||||
|
||||
|
||||
def test_hazard3_debug_flow_is_locked_and_uses_remote_bitbang() -> None:
|
||||
lock = load_lock(ROOT / "config/dependencies.lock.json")
|
||||
makefile = (ROOT / "Makefile").read_text(encoding="utf-8")
|
||||
wrapper = (ROOT / "rtl/mini/top/mgmt_core_wrapper.sv").read_text(encoding="utf-8")
|
||||
debug_wrapper = (ROOT / "rtl/mini/top/mgmt_debug_wrapper.sv").read_text(encoding="utf-8")
|
||||
verilator_makefile = (ROOT / "rtl/mini/mk/verilator.mk").read_text(encoding="utf-8")
|
||||
driver = (ROOT / "scripts/run_debug_session.py").read_text(encoding="utf-8")
|
||||
openocd = (ROOT / "rtl/mini/dv/verilator/openocd/retrosoc_hazard3.cfg").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
|
||||
assert "HAVE_DEBUG ?= YES" in makefile
|
||||
assert "JTAG_IDCODE ?= DEADBEEF" in makefile
|
||||
assert "if [ $$value -gt 2147483647 ]" in makefile
|
||||
assert "HAVE_DEBUG=YES requires CORE=HAZARD3" in makefile
|
||||
assert ".MULDIV_UNROLL (2)" in wrapper
|
||||
assert ".BRANCH_PREDICTOR (1)" in wrapper
|
||||
assert ".BREAKPOINT_TRIGGERS(2)" in wrapper
|
||||
assert ".HAVE_SBA(0)" in debug_wrapper
|
||||
assert "mgmt_debug_reset u_mgmt_debug_reset" in debug_wrapper
|
||||
assert "--timeout $(SOC_SIM_TIME)" in verilator_makefile
|
||||
assert "DEBUG_GDB_PASS" in driver
|
||||
assert "break *0x30000008" in driver
|
||||
assert "adapter driver remote_bitbang" in openocd
|
||||
assert "-expected-id 0xdeadbeef" in openocd
|
||||
assert lock["toolchains"]["ubuntu-22.04"]["openocd"]["version"] == "0.12.0-1"
|
||||
assert any(profile == "configs/ci/ihp130-debug.mk" for profile, _ in PR_COMMANDS)
|
||||
|
||||
|
||||
def test_benchmark_profile_uses_functional_sram_and_reserved_data() -> None:
|
||||
makefile = (ROOT / "Makefile").read_text(encoding="utf-8")
|
||||
profile = (ROOT / "configs/benchmark/ihp130-hazard3.mk").read_text(encoding="utf-8")
|
||||
|
||||
@@ -47,8 +47,11 @@ def test_core_sdc_covers_current_clock_domains(tmp_path: Path) -> None:
|
||||
assert "create_clock -name clk_external -period 13.888888889" in sdc
|
||||
assert "create_generated_clock -name clk_system" in sdc
|
||||
assert "create_clock -name clk_audio -period 54.253472222" in sdc
|
||||
assert "create_clock -name clk_jtag -period 100" in sdc
|
||||
assert "create_clock -name clk_dvp -period 41.666666667" in sdc
|
||||
assert "get_pins -quiet" in sdc
|
||||
assert "get_ports -quiet" in sdc
|
||||
assert "set clk_jtag_port [require_ports \"clock jtag\" {jtag_tck_i_pad}]" in sdc
|
||||
assert "u_retrosoc.u_ip_ribp_wrapper.u_rib_dvp.u_dvp_pclk_clk_buf/clk_o" in sdc
|
||||
assert "-group [get_clocks {clk_external clk_system}]" in sdc
|
||||
assert "set_clock_transition 0.1 [get_clocks {clk_dvp}]" in sdc
|
||||
|
||||
Reference in new issue
Block a user