feat: add RTL linting support with Verilator integration

- Introduced RTL linting capabilities using Verilator in the Makefile.
- Added RTL_LINT_FLAGS for specifying linting options and created targets for linting.
- Implemented a new script to analyze RTL lint warnings and check against a baseline.
- Updated regression scripts to include RTL linting in the command sets.
- Enhanced test coverage for RTL linting functionality, ensuring proper warning handling.
- Cleaned up build directories to include RTL lint outputs.
This commit is contained in:
maksyuki committed 2026-07-25 09:14:29 +08:00
1 parent 65d974395d
commit 6f0e053d58
11 files changed
+9288 -25

No files matched your search

+11 -10
View File
@@ -16,6 +16,9 @@ sys.path.insert(0, str(ROOT))
from scripts.setup_helpers import atomic_write # noqa: E402
WARNING_TOOLS = ("iverilog", "verilator", "rtl-lint", "vcs", "yosys", "opensta")
ANSI_RE = re.compile(r"\x1b\[[0-9;]*m")
TIMESTAMP_RE = re.compile(r"^\[[^]]+\]\s*")
LOCATION_RE = re.compile(
@@ -28,6 +31,7 @@ LOCATION_RE = re.compile(
def warning_line(tool: str, line: str) -> tuple[str, str] | None:
patterns = {
"verilator": re.compile(r"%Warning-([A-Z0-9_]+):\s*(.*)"),
"rtl-lint": re.compile(r"%Warning-([A-Z0-9_]+):\s*(.*)"),
"iverilog": re.compile(r"\b(warning|sorry):\s*(.*)", re.IGNORECASE),
"yosys": re.compile(r"\b(?:ABC:\s*)?Warning:\s*(.*)", re.IGNORECASE),
"opensta": re.compile(r"\bWarning\s+(\d+):\s*(.*)", re.IGNORECASE),
@@ -36,7 +40,7 @@ def warning_line(tool: str, line: str) -> tuple[str, str] | None:
match = patterns[tool].search(line)
if not match:
return None
if tool in ("verilator", "opensta"):
if tool in ("verilator", "rtl-lint", "opensta"):
return match.group(1), match.group(2)
if tool == "iverilog":
return match.group(1).lower(), match.group(2)
@@ -84,6 +88,7 @@ def discover(variant_root: Path) -> dict[str, list[Path]]:
return {
"iverilog": sorted((variant_root / "sim/iverilog").glob("*/*.log")),
"verilator": sorted((variant_root / "sim/verilator").glob("*.log")),
"rtl-lint": sorted((variant_root / "lint/verilator").glob("lint.log")),
"vcs": sorted((variant_root / "sim/vcs").glob("*/*.log")),
"yosys": sorted((variant_root / "syn/yosys").glob("*.log")),
"opensta": sorted((variant_root / "sta/opensta").glob("*.log")),
@@ -106,7 +111,7 @@ def write_baseline(args: argparse.Namespace) -> int:
def check(args: argparse.Namespace) -> int:
root = args.root.resolve()
variant_root = args.variant_root.resolve()
tools = [args.tool] if args.tool else ["iverilog", "verilator", "vcs", "yosys", "opensta"]
tools = [args.tool] if args.tool else WARNING_TOOLS
logs = discover(variant_root)
reports: dict[str, object] = {}
failures: list[str] = []
@@ -119,12 +124,8 @@ def check(args: argparse.Namespace) -> int:
baseline_entries: dict[str, int] = {}
if baseline_path.is_file():
baseline = json.loads(baseline_path.read_text(encoding="utf-8"))
baseline_entries = {
entry["signature"]: entry["count"] for entry in baseline["entries"]
}
current_entries = {
entry["signature"]: entry["count"] for entry in current["entries"]
}
baseline_entries = {entry["signature"]: entry["count"] for entry in baseline["entries"]}
current_entries = {entry["signature"]: entry["count"] for entry in current["entries"]}
new = sorted(set(current_entries) - set(baseline_entries))
increased = sorted(
signature
@@ -159,14 +160,14 @@ def parse_args() -> argparse.Namespace:
baseline = subparsers.add_parser("baseline")
baseline.add_argument("--root", type=Path, default=ROOT)
baseline.add_argument("--profile", required=True)
baseline.add_argument("--tool", choices=("iverilog", "verilator", "vcs", "yosys", "opensta"), required=True)
baseline.add_argument("--tool", choices=WARNING_TOOLS, required=True)
baseline.add_argument("--log", type=Path, action="append", required=True)
baseline.add_argument("--output", type=Path, required=True)
check_parser = subparsers.add_parser("check")
check_parser.add_argument("--root", type=Path, default=ROOT)
check_parser.add_argument("--profile", required=True)
check_parser.add_argument("--variant-root", type=Path, required=True)
check_parser.add_argument("--tool", choices=("iverilog", "verilator", "vcs", "yosys", "opensta"))
check_parser.add_argument("--tool", choices=WARNING_TOOLS)
check_parser.add_argument("--output", type=Path, required=True)
return parser.parse_args()
+6
View File
@@ -15,7 +15,11 @@ sys.path.insert(0, str(ROOT))
from scripts.check_c_warnings import self_owned_warnings # noqa: E402
RTL_LINT_VALUES = ("SIMU=VERILATOR", "HAVE_SVA=YES", "rtl-lint", "check-rtl-lint")
PR_COMMANDS = (
("configs/ci/hazard3-rv32im-ihp130.mk", RTL_LINT_VALUES),
("configs/ci/hazard3-rv32im-ihp130.mk", ("firmware",)),
("configs/ci/hazard3-rv32im-ihp130-shell.mk", ("firmware",)),
("configs/ci/hazard3-rv32im-ihp130-ip-mdd-shell.mk", ("firmware",)),
@@ -49,6 +53,7 @@ PR_COMMANDS = (
("configs/ci/hazard3-rv32im-ihp130.mk", ("STA=OPENSTA", "sta")),
)
SMOKE_COMMANDS = (
("configs/ci/hazard3-rv32im-ihp130.mk", RTL_LINT_VALUES),
("configs/ci/hazard3-rv32im-ihp130.mk", ("firmware",)),
(
"configs/ci/hazard3-rv32im-ihp130.mk",
@@ -86,6 +91,7 @@ PDK_PR_PROFILES = {
def pdk_pr_commands(profile: str) -> tuple[tuple[str, tuple[str, ...]], ...]:
return (
(profile, RTL_LINT_VALUES),
(profile, ("firmware",)),
(profile, ("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim")),
(profile, ("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm")),