From 201d0273dc3164dee98993d8b5644337b567b99b Mon Sep 17 00:00:00 2001 From: htfab Date: Thu, 26 Mar 2026 13:05:34 +0100 Subject: [PATCH] feat(precheck): add Verilog syntax check --- precheck/precheck.py | 25 +++++++++++++++++++++++++ precheck/pyproject.toml | 1 + precheck/requirements.txt | 12 +++++++++++- precheck/test_precheck.py | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/precheck/precheck.py b/precheck/precheck.py index 9b5dfec..74e485c 100644 --- a/precheck/precheck.py +++ b/precheck/precheck.py @@ -308,6 +308,27 @@ def analog_pin_check( ) +def verilog_syntax_check(verilog: str): + """Load the Verilog file into Yosys to verify it can be read successfully.""" + + logging.info(f"Running Verilog syntax check on {verilog}") + verilog_dir = os.path.dirname(verilog) + yowasp_env = os.environ.copy() + yowasp_env["YOWASP_MOUNT"] = f"{verilog_dir}={verilog_dir}" + + yosys = subprocess.run( + [ + "yowasp-yosys", + "-p", + f'read_verilog -sv "{verilog}"', + ], + env=yowasp_env, + ) + + if yosys.returncode != 0: + raise PrecheckFailure("Verilog syntax check failed") + + def main(): default_tech = PDK_NAME if default_tech not in tech_names: @@ -447,6 +468,10 @@ def main(): ), "techs": ["sky130A", "ihp-sg13g2"], }, + { + "name": "Verilog syntax check", + "check": lambda: verilog_syntax_check(verilog_file), + }, ] testsuite = ET.Element("testsuite", name="Tiny Tapeout Prechecks") diff --git a/precheck/pyproject.toml b/precheck/pyproject.toml index 9b68a34..9008317 100644 --- a/precheck/pyproject.toml +++ b/precheck/pyproject.toml @@ -8,6 +8,7 @@ dependencies = [ "numpy<2", "pytest", "PyYAML", + "yowasp-yosys", ] [tool.setuptools] diff --git a/precheck/requirements.txt b/precheck/requirements.txt index 83c6340..5c8faa9 100644 --- a/precheck/requirements.txt +++ b/precheck/requirements.txt @@ -1,9 +1,11 @@ # -# This file is autogenerated by pip-compile with Python 3.12 +# This file is autogenerated by pip-compile with Python 3.13 # by the following command: # # pip-compile # +click==8.3.1 + # via yowasp-yosys gdstk==0.9.52 # via tt-precheck (pyproject.toml) iniconfig==2.0.0 @@ -16,9 +18,17 @@ numpy==1.26.4 # tt-precheck (pyproject.toml) packaging==24.1 # via pytest +platformdirs==4.9.4 + # via yowasp-runtime pluggy==1.5.0 # via pytest pytest==8.2.2 # via tt-precheck (pyproject.toml) pyyaml==6.0.1 # via tt-precheck (pyproject.toml) +wasmtime==42.0.0 + # via yowasp-runtime +yowasp-runtime==1.88 + # via yowasp-yosys +yowasp-yosys==0.63.0.0.post1107 + # via tt-precheck (pyproject.toml) diff --git a/precheck/test_precheck.py b/precheck/test_precheck.py index b2c6871..6e35427 100644 --- a/precheck/test_precheck.py +++ b/precheck/test_precheck.py @@ -537,6 +537,31 @@ def gds_lef_analog_pin_example(tmp_path_factory: pytest.TempPathFactory): return str(gds_file), str(lef_file) +@pytest.fixture(scope="session") +def verilog_syntax_ok(tmp_path_factory: pytest.TempPathFactory): + """Creates a Verilog file with correct syntax.""" + verilog_file = tmp_path_factory.mktemp("verilog") / "TEST_verilog_syntax_ok.v" + verilog_data = """ + module TEST_verilog_syntax_ok (); + endmodule + """ + open(verilog_file, "w").write(textwrap.dedent(verilog_data)) + return str(verilog_file) + + +@pytest.fixture(scope="session") +def verilog_syntax_error(tmp_path_factory: pytest.TempPathFactory): + """Creates a Verilog file with incorrect syntax.""" + verilog_file = tmp_path_factory.mktemp("verilog") / "TEST_verilog_syntax_error.v" + verilog_data = """ + module TEST_verilog_syntax_error (); + syntax error + endmodule + """ + open(verilog_file, "w").write(textwrap.dedent(verilog_data)) + return str(verilog_file) + + def test_magic_drc_pass(gds_valid: str): precheck.magic_drc(gds_valid, "TEST_valid") @@ -822,3 +847,15 @@ def test_analog_more_ua_entries(gds_lef_analog_pin_example: tuple[str, str]): 2, {"ua[0]": "x", "ua[1]": "x", "ua[2]": "x"}, ) + + +def test_verilog_syntax_ok(verilog_syntax_ok: str): + precheck.verilog_syntax_check(verilog_syntax_ok) + + +def test_verilog_syntax_error(verilog_syntax_error: str): + with pytest.raises( + precheck.PrecheckFailure, + match="Verilog syntax check failed", + ): + precheck.verilog_syntax_check(verilog_syntax_error)