feat: update HP Linux configuration validation and adjust simulation time

This commit is contained in:
maksyuki committed 2026-09-25 11:22:13 +08:00
1 parent 95ee570a44
commit 75ed04e7ef
7 files changed
+286 -84

No files matched your search

+2 -2
View File
@@ -131,7 +131,7 @@ HP_BOOT_BUNDLE_NAME ?= retrosoc_hp_linux
HP_BOOT_BUNDLE_BIN := $(SW_BUILD_DIR)/$(HP_BOOT_BUNDLE_NAME).bin
HP_BOOT_BUNDLE_HEX := $(SW_BUILD_DIR)/$(HP_BOOT_BUNDLE_NAME).hex
HP_BOOT_BUNDLE_MANIFEST := $(SW_BUILD_DIR)/$(HP_BOOT_BUNDLE_NAME).json
HP_LINUX_SIM_TIME ?= 7200
HP_LINUX_SIM_TIME ?= 0
HP_SMOKE_SIM_TIME ?= 300
HP_SMOKE_BUILD_DIR := $(VARIANT_ROOT)/hp-smoke
HP_SMOKE_STAMP := $(HP_SMOKE_BUILD_DIR)/images/.stamp
@@ -731,4 +731,4 @@ regress-nightly:
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite nightly
sim-asm: asm
$(MAKE) SIM_FIRMWARE_NAME=$(ASM_FIRMWARE_NAME) sim
$(MAKE) SIM_FIRMWARE_NAME=$(ASM_FIRMWARE_NAME) sim
+4
View File
@@ -5,6 +5,10 @@ CONFIG_RISCV_ISA_A=y
CONFIG_RISCV_ISA_C=y
CONFIG_FPU=y
CONFIG_SMP=n
CONFIG_PRINTK=y
CONFIG_TTY=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_SCRIPT=y
CONFIG_HVC_RISCV_SBI=y
CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
CONFIG_SIFIVE_PLIC=y
@@ -5222,7 +5222,7 @@
{
"id": "kernel-sbi",
"file": "app/ports/linux/linux/retrosoc_hp.config",
"text": "CONFIG_SMP=n\nCONFIG_HVC_RISCV_SBI=y\nCONFIG_SERIAL_EARLYCON_RISCV_SBI=y"
"text": "CONFIG_SMP=n\nCONFIG_PRINTK=y\nCONFIG_TTY=y\nCONFIG_BINFMT_ELF=y\nCONFIG_BINFMT_SCRIPT=y\nCONFIG_HVC_RISCV_SBI=y\nCONFIG_SERIAL_EARLYCON_RISCV_SBI=y"
},
{
"id": "kernel-ready-support",
+110 -80
View File
@@ -108,11 +108,11 @@ module axi4_data_crossbar #(
logic user;
} read_resp_t;
addr_channel_t m_aw [NumMasters];
addr_channel_t m_ar [NumMasters];
write_channel_t m_w [NumMasters];
write_resp_t m_b [NumMasters];
read_resp_t m_r [NumMasters];
addr_channel_t m_aw [NumMasters];
addr_channel_t m_ar [NumMasters];
write_channel_t m_w [NumMasters];
write_resp_t m_b [NumMasters];
read_resp_t m_r [NumMasters];
logic [NumMasters-1:0] m_awvalid;
logic [NumMasters-1:0] m_awready;
logic [NumMasters-1:0] m_wvalid;
@@ -124,11 +124,11 @@ module axi4_data_crossbar #(
logic [NumMasters-1:0] m_rvalid;
logic [NumMasters-1:0] m_rready;
addr_channel_t t_aw [NumTargets];
addr_channel_t t_ar [NumTargets];
write_channel_t t_w [NumTargets];
write_resp_t t_b [NumTargets];
read_resp_t t_r [NumTargets];
addr_channel_t t_aw [NumTargets];
addr_channel_t t_ar [NumTargets];
write_channel_t t_w [NumTargets];
write_resp_t t_b [NumTargets];
read_resp_t t_r [NumTargets];
logic [NumTargets-1:0] t_awvalid;
logic [NumTargets-1:0] t_awready;
logic [NumTargets-1:0] t_wvalid;
@@ -154,6 +154,7 @@ module axi4_data_crossbar #(
logic [NumTargets-1:0] s_write_capture;
logic [NumMasters-1:0][ NumTargets-1:0] s_read_resp_req;
logic [NumMasters-1:0][ NumTargets-1:0] s_read_resp_arb_req;
logic [NumMasters-1:0][ NumTargets-1:0] s_write_resp_req;
logic [NumMasters-1:0][ NumTargets-1:0] unused_read_resp_grant;
logic [NumMasters-1:0][ NumTargets-1:0] unused_write_resp_grant;
@@ -163,27 +164,30 @@ module axi4_data_crossbar #(
logic [NumMasters-1:0] s_write_resp_valid;
logic [NumMasters-1:0] s_read_terminal;
logic [NumMasters-1:0] s_write_terminal;
logic [NumTargets-1:0] s_invalid_read_response;
logic [NumTargets-1:0] s_invalid_write_response;
logic [NumTargets-1:0] s_invalid_read_fault_accept;
logic [NumTargets-1:0] s_invalid_write_fault_accept;
logic s_protocol_fault_pending;
logic s_protocol_fault_event;
logic s_protocol_recovery_q;
logic [NumMasters-1:0] s_read_resp_lock_d, s_read_resp_lock_q;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_resp_lock_target_d;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_resp_lock_target_q;
logic [NumTargets-1:0] s_invalid_read_response;
logic [NumTargets-1:0] s_invalid_write_response;
logic [NumTargets-1:0] s_invalid_read_fault_accept;
logic [NumTargets-1:0] s_invalid_write_fault_accept;
logic s_protocol_fault_pending;
logic s_protocol_fault_event;
logic s_protocol_recovery_q;
logic [NumTargets-1:0] s_target_write_owner_full;
logic [NumTargets-1:0] s_target_write_owner_empty;
logic [NumTargets-1:0] s_target_write_owner_push;
logic [NumTargets-1:0] s_target_write_owner_pop;
logic [NumTargets-1:0][MasterWidth-1:0] s_target_write_owner_data;
logic [NumTargets-1:0][ 1:0] unused_target_write_owner_count;
logic [NumTargets-1:0] s_target_write_owner_full;
logic [NumTargets-1:0] s_target_write_owner_empty;
logic [NumTargets-1:0] s_target_write_owner_push;
logic [NumTargets-1:0] s_target_write_owner_pop;
logic [NumTargets-1:0][MasterWidth-1:0] s_target_write_owner_data;
logic [NumTargets-1:0][ 1:0] unused_target_write_owner_count;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_decoded_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_write_decoded_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_routed_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_write_routed_target;
logic [NumMasters-1:0][ 3:0] s_read_fault_reason;
logic [NumMasters-1:0][ 3:0] s_write_fault_reason;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_decoded_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_write_decoded_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_routed_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_write_routed_target;
logic [NumMasters-1:0][ 3:0] s_read_fault_reason;
logic [NumMasters-1:0][ 3:0] s_write_fault_reason;
logic [NumMasters-1:0][CountWidth-1:0] s_master_read_count_d, s_master_read_count_q;
logic [NumMasters-1:0][CountWidth-1:0] s_master_write_count_d, s_master_write_count_q;
@@ -388,7 +392,7 @@ module axi4_data_crossbar #(
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.advance_i (s_read_terminal[master]),
.request_i (s_read_resp_req[master]),
.request_i (s_read_resp_arb_req[master]),
.grant_o (unused_read_resp_grant[master]),
.selected_o(s_read_resp_selected[master]),
.valid_o (s_read_resp_valid[master])
@@ -406,6 +410,20 @@ module axi4_data_crossbar #(
);
end
always_comb begin
// Keep all beats of one read burst on its selected target. AXI read
// responses may complete out of order by ID, but beats of a burst must
// not be interleaved with another target's burst on the same master.
s_read_resp_arb_req = s_read_resp_req;
for (int master = 0; master < NumMasters; master++) begin
if (s_read_resp_lock_q[master]) begin
s_read_resp_arb_req[master] = '0;
s_read_resp_arb_req[master][s_read_resp_lock_target_q[master]] =
s_read_resp_req[master][s_read_resp_lock_target_q[master]];
end
end
end
for (genvar target = 0; target < NumTargets; target++) begin : gen_target_ports
assign targets[target].awid = t_aw[target].id;
assign targets[target].awaddr = t_aw[target].addr;
@@ -846,18 +864,24 @@ module axi4_data_crossbar #(
end
always_comb begin
s_master_read_count_d = s_master_read_count_q;
s_master_write_count_d = s_master_write_count_q;
s_target_read_count_d = s_target_read_count_q;
s_target_write_count_d = s_target_write_count_q;
s_read_id_busy_d = s_read_id_busy_q;
s_write_id_busy_d = s_write_id_busy_q;
s_master_read_count_d = s_master_read_count_q;
s_master_write_count_d = s_master_write_count_q;
s_target_read_count_d = s_target_read_count_q;
s_target_write_count_d = s_target_write_count_q;
s_read_id_busy_d = s_read_id_busy_q;
s_write_id_busy_d = s_write_id_busy_q;
s_read_resp_lock_d = s_read_resp_lock_q;
s_read_resp_lock_target_d = s_read_resp_lock_target_q;
for (int master = 0; master < NumMasters; master++) begin
if (s_read_terminal[master]) begin
s_master_read_count_d[master] = s_master_read_count_d[master] - 1'b1;
s_target_read_count_d[s_read_resp_selected[master]] =
s_target_read_count_d[s_read_resp_selected[master]] - 1'b1;
s_read_id_busy_d[master][s_read_complete_id[master]] = 1'b0;
s_read_resp_lock_d[master] = 1'b0;
end else if (!s_read_resp_lock_q[master] && s_read_resp_valid[master]) begin
s_read_resp_lock_d[master] = 1'b1;
s_read_resp_lock_target_d[master] = s_read_resp_selected[master];
end
if (s_write_terminal[master]) begin
s_master_write_count_d[master] = s_master_write_count_d[master] - 1'b1;
@@ -972,53 +996,59 @@ module axi4_data_crossbar #(
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_master_read_count_q <= '0;
s_master_write_count_q <= '0;
s_target_read_count_q <= '0;
s_target_write_count_q <= '0;
s_read_id_busy_q <= '0;
s_write_id_busy_q <= '0;
s_write_route_q <= '0;
s_route_read_ptr_q <= '0;
s_route_write_ptr_q <= '0;
s_route_count_q <= '0;
s_read_age_q <= '0;
s_write_age_q <= '0;
s_protocol_recovery_q <= 1'b0;
fault_valid_o <= 1'b0;
fault_master_o <= '0;
fault_target_o <= '0;
fault_addr_o <= '0;
fault_write_o <= 1'b0;
fault_reason_o <= '0;
s_master_read_count_q <= '0;
s_master_write_count_q <= '0;
s_target_read_count_q <= '0;
s_target_write_count_q <= '0;
s_read_id_busy_q <= '0;
s_write_id_busy_q <= '0;
s_read_resp_lock_q <= '0;
s_read_resp_lock_target_q <= '0;
s_write_route_q <= '0;
s_route_read_ptr_q <= '0;
s_route_write_ptr_q <= '0;
s_route_count_q <= '0;
s_read_age_q <= '0;
s_write_age_q <= '0;
s_protocol_recovery_q <= 1'b0;
fault_valid_o <= 1'b0;
fault_master_o <= '0;
fault_target_o <= '0;
fault_addr_o <= '0;
fault_write_o <= 1'b0;
fault_reason_o <= '0;
end else begin
if (flush_i) begin
s_master_read_count_q <= '0;
s_master_write_count_q <= '0;
s_target_read_count_q <= '0;
s_target_write_count_q <= '0;
s_read_id_busy_q <= '0;
s_write_id_busy_q <= '0;
s_write_route_q <= '0;
s_route_read_ptr_q <= '0;
s_route_write_ptr_q <= '0;
s_route_count_q <= '0;
s_read_age_q <= '0;
s_write_age_q <= '0;
s_protocol_recovery_q <= 1'b0;
s_master_read_count_q <= '0;
s_master_write_count_q <= '0;
s_target_read_count_q <= '0;
s_target_write_count_q <= '0;
s_read_id_busy_q <= '0;
s_write_id_busy_q <= '0;
s_read_resp_lock_q <= '0;
s_read_resp_lock_target_q <= '0;
s_write_route_q <= '0;
s_route_read_ptr_q <= '0;
s_route_write_ptr_q <= '0;
s_route_count_q <= '0;
s_read_age_q <= '0;
s_write_age_q <= '0;
s_protocol_recovery_q <= 1'b0;
end else begin
s_master_read_count_q <= s_master_read_count_d;
s_master_write_count_q <= s_master_write_count_d;
s_target_read_count_q <= s_target_read_count_d;
s_target_write_count_q <= s_target_write_count_d;
s_read_id_busy_q <= s_read_id_busy_d;
s_write_id_busy_q <= s_write_id_busy_d;
s_write_route_q <= s_write_route_d;
s_route_read_ptr_q <= s_route_read_ptr_d;
s_route_write_ptr_q <= s_route_write_ptr_d;
s_route_count_q <= s_route_count_d;
s_read_age_q <= s_read_age_d;
s_write_age_q <= s_write_age_d;
s_master_read_count_q <= s_master_read_count_d;
s_master_write_count_q <= s_master_write_count_d;
s_target_read_count_q <= s_target_read_count_d;
s_target_write_count_q <= s_target_write_count_d;
s_read_id_busy_q <= s_read_id_busy_d;
s_write_id_busy_q <= s_write_id_busy_d;
s_read_resp_lock_q <= s_read_resp_lock_d;
s_read_resp_lock_target_q <= s_read_resp_lock_target_d;
s_write_route_q <= s_write_route_d;
s_route_read_ptr_q <= s_route_read_ptr_d;
s_route_write_ptr_q <= s_route_write_ptr_d;
s_route_count_q <= s_route_count_d;
s_read_age_q <= s_read_age_d;
s_write_age_q <= s_write_age_d;
if (s_protocol_fault_event) s_protocol_recovery_q <= 1'b1;
end
if (!fault_valid_o || fault_ready_i) begin
+31
View File
@@ -19,6 +19,15 @@ LAYOUT = {
"rootfs.cpio.gz": (0x39000000, 8 * 1024 * 1024),
}
REQUIRED_LINUX_CONFIG = (
"CONFIG_BINFMT_ELF",
"CONFIG_BINFMT_SCRIPT",
"CONFIG_PRINTK",
"CONFIG_TTY",
"CONFIG_HVC_RISCV_SBI",
"CONFIG_SERIAL_EARLYCON_RISCV_SBI",
)
def command(arguments: list[str], cwd: Path) -> None:
environment = dict(os.environ)
@@ -57,6 +66,27 @@ def find_toolchain(buildroot_output: Path) -> str:
return str(matches[0])[: -len("gcc")]
def validate_linux_config(config: Path) -> None:
values: dict[str, str] = {}
for line in config.read_text(encoding="utf-8").splitlines():
if line.startswith("CONFIG_") and "=" in line:
symbol, value = line.split("=", 1)
values[symbol] = value
elif line.startswith("# CONFIG_") and line.endswith(" is not set"):
symbol = line[len("# ") : -len(" is not set")]
values[symbol] = "n"
invalid = [
f"{symbol}={values.get(symbol, 'missing')}"
for symbol in REQUIRED_LINUX_CONFIG
if values.get(symbol) != "y"
]
if invalid:
raise RuntimeError(
"invalid HP Linux effective configuration: " + ", ".join(invalid)
)
def build(args: argparse.Namespace) -> None:
root = args.root.resolve()
output = args.output.resolve()
@@ -94,6 +124,7 @@ def build(args: argparse.Namespace) -> None:
["make", f"O={linux_output}", "ARCH=riscv", f"CROSS_COMPILE={cross_compile}", "olddefconfig"],
linux,
)
validate_linux_config(linux_output / ".config")
command(
["make", f"O={linux_output}", "ARCH=riscv", f"CROSS_COMPILE={cross_compile}",
f"-j{args.jobs}", "Image"],
+111
View File
@@ -98,6 +98,54 @@ module axi4_data_crossbar_tb;
end
endtask
task automatic issue_master1_read_burst(input logic [6:0] id, input logic [31:0] addr);
begin
@(negedge clk_i);
masters[1].arid = id;
masters[1].araddr = addr;
masters[1].arlen = 8'd7;
masters[1].arsize = 3'd3;
masters[1].arburst = 2'b01;
masters[1].arvalid = 1'b1;
do @(posedge clk_i); while (!masters[1].arready);
@(negedge clk_i);
masters[1].arvalid = 1'b0;
masters[1].arlen = '0;
end
endtask
task automatic return_target0_burst(input logic [6:0] id, input logic [63:0] data_base);
begin
for (int unsigned beat = 0; beat < 8; beat++) begin
@(negedge clk_i);
targets[0].rid = id;
targets[0].rdata = data_base + beat;
targets[0].rresp = 2'b00;
targets[0].rlast = (beat == 7);
targets[0].rvalid = 1'b1;
do @(posedge clk_i); while (!targets[0].rready);
@(negedge clk_i);
targets[0].rvalid = 1'b0;
end
end
endtask
task automatic return_target1_burst(input logic [6:0] id, input logic [63:0] data_base);
begin
for (int unsigned beat = 0; beat < 8; beat++) begin
@(negedge clk_i);
targets[1].rid = id;
targets[1].rdata = data_base + beat;
targets[1].rresp = 2'b00;
targets[1].rlast = (beat == 7);
targets[1].rvalid = 1'b1;
do @(posedge clk_i); while (!targets[1].rready);
@(negedge clk_i);
targets[1].rvalid = 1'b0;
end
end
endtask
task automatic return_target0_read(input logic [6:0] id, input logic [63:0] data);
begin
@(negedge clk_i);
@@ -405,6 +453,69 @@ module axi4_data_crossbar_tb;
$fatal(1, "same-target reads did not drain the crossbar");
end
read_burst_target_lock : begin
logic [ 6:0] first_id;
logic [ 6:0] second_id;
logic [63:0] first_base;
logic [63:0] second_base;
logic [ 6:0] expected_id;
logic [63:0] expected_data;
issue_master1_read_burst(6'b001_100, 32'h3000_0200);
issue_master1_read_burst(6'b001_101, 32'h3800_0200);
if (outstanding_read_o != 8'd2) begin
$fatal(1, "read bursts were not tracked concurrently");
end
fork
return_target0_burst(6'b001_100, 64'hAAAA_0000_0000_0000);
return_target1_burst(6'b001_101, 64'hBBBB_0000_0000_0000);
begin
for (int unsigned beat = 0; beat < 16; beat++) begin
do begin
@(negedge clk_i);
#1;
end while (!masters[1].rvalid);
if (beat == 0) begin
first_id = masters[1].rid;
if (first_id == 6'b001_100) begin
first_base = 64'hAAAA_0000_0000_0000;
second_id = 6'b001_101;
second_base = 64'hBBBB_0000_0000_0000;
end else if (first_id == 6'b001_101) begin
first_base = 64'hBBBB_0000_0000_0000;
second_id = 6'b001_100;
second_base = 64'hAAAA_0000_0000_0000;
end else begin
$fatal(1, "read burst returned an unexpected ID");
end
end
if (beat < 8) begin
expected_id = first_id;
expected_data = first_base + beat;
end else begin
expected_id = second_id;
expected_data = second_base + (beat - 8);
end
if ((masters[1].rid != expected_id) || (masters[1].rdata != expected_data) ||
(masters[1].rlast != (beat == 7 || beat == 15))) begin
$fatal(
1,
"read response burst was interleaved or malformed at beat %0d rid=%h expected_id=%h data=%h expected_data=%h last=%b expected_last=%b",
beat, masters[1].rid, expected_id, masters[1].rdata, expected_data,
masters[1].rlast, (beat == 7 || beat == 15));
end
end
end
join
@(negedge clk_i);
if (!idle_o || (outstanding_read_o != 8'd0)) begin
$fatal(1, "read burst target lock did not drain the crossbar");
end
end
jpeg_master_admission_credit_priority_and_acl : begin
// JPEG's normal class is above the LP gateway's class before aging.
@(negedge clk_i);
+27 -1
View File
@@ -7,6 +7,10 @@ import shutil
import subprocess
from pathlib import Path
import pytest
from scripts import build_hp_linux
ROOT = Path(__file__).resolve().parents[1]
@@ -50,7 +54,7 @@ def test_hp_linux_simulation_uses_explicit_fast_flash_acceptance() -> None:
verilator_makefile = (ROOT / "rtl/mini/mk/verilator.mk").read_text(encoding="utf-8")
emulator = (ROOT / "rtl/mini/dv/verilator/csrc/main.cpp").read_text(encoding="utf-8")
assert "HP_LINUX_SIM_TIME ?= 7200" in makefile
assert "HP_LINUX_SIM_TIME ?= 0" in makefile
assert "hp-linux-sim: hp-bundle comp" in makefile
assert "VERILATOR_SIM_ARGS=--fast-flash sim" in makefile
for marker in (
@@ -157,6 +161,28 @@ def test_linux_build_uses_external_opensbi_platform_and_actual_initrd_end() -> N
assert "aclint_mtimer_cold_init" in platform
def test_hp_linux_effective_config_is_fail_closed(tmp_path: Path) -> None:
fragment = (ROOT / "app/ports/linux/linux/retrosoc_hp.config").read_text(
encoding="utf-8"
)
for symbol in build_hp_linux.REQUIRED_LINUX_CONFIG:
assert f"{symbol}=y" in fragment
config = tmp_path / ".config"
valid = "".join(f"{symbol}=y\n" for symbol in build_hp_linux.REQUIRED_LINUX_CONFIG)
config.write_text(valid, encoding="utf-8")
build_hp_linux.validate_linux_config(config)
config.write_text(valid.replace("CONFIG_BINFMT_ELF=y", "# CONFIG_BINFMT_ELF is not set"),
encoding="utf-8")
with pytest.raises(RuntimeError, match="CONFIG_BINFMT_ELF=n"):
build_hp_linux.validate_linux_config(config)
config.write_text(valid.replace("CONFIG_TTY=y\n", ""), encoding="utf-8")
with pytest.raises(RuntimeError, match="CONFIG_TTY=missing"):
build_hp_linux.validate_linux_config(config)
def test_hp_linux_device_tree_compiles_and_can_patch_initrd_end(tmp_path: Path) -> None:
dtc = shutil.which("dtc")
fdtput = shutil.which("fdtput")