Architecture

svhier parses SystemVerilog files using the pyslang C++ extension (slang elaborator) and outputs a module/instance hierarchy as YAML.

Parser

svhier.parser.parse_files

Parse a list of SystemVerilog files and return the module/instance hierarchy.

svhier.parser.compute_filelist

Return file paths in topological dependency order (dependencies first).

svhier.parser.parse_files(file_paths: list[str]) dict

Parse a list of SystemVerilog files and return the module/instance hierarchy.

All files share a single SourceManager so cross-file instantiation resolves correctly. See the module docstring for the two-phase elaboration model.

Returns a dict with the following top-level keys:

files

One entry per input file, each containing:

  • file_name — original caller string (not resolved).

  • pkgs — package names defined in this file (internal bookkeeping, stripped from YAML output by svhier.cli._prepare_for_yaml()).

  • defs — list of module definitions, each with mod_name, pkg_imports (omitted from YAML when empty), and insts (list of {"mod_name": str, "inst_name": str}).

diagnostics

List of {"severity": str, "file": str, "message": str} dicts from pyslang’s DiagnosticEngine (internal; stripped from YAML output).

has_errors

True if any error-level diagnostic was issued. The CLI exits with code 1 when this is set.

Note

Modules that are defined but never instantiated are unreachable via topInstances and will appear in the output with an empty insts list.

svhier.parser.compute_filelist(result: dict) list[str]

Return file paths in topological dependency order (dependencies first).

Builds a networkx.DiGraph where an edge A B means file A must be compiled before file B. Edges come from two sources:

  • Module instantiation — a file that instantiates a module depends on the file that defines it.

  • Package imports — a file that imports a package depends on the file that defines it.

nx.topological_sort produces the compilation order. If the graph contains a cycle the original input order is returned unchanged.

result is the dict returned by parse_files().

Tip

If your design has genuine circular dependencies between files, the filelist falls back to the original input order rather than raising an error.

CLI

svhier.cli.collect_sv_files

Expand a mix of .sv/.v files and directories into a deduplicated file list.

svhier.cli.collect_inc_dirs

Return directories that contain .svh/.vh header files under paths.

svhier.cli.main

Entry point: parse arguments, run slang elaboration, emit YAML and optional filelist.

svhier.cli.collect_sv_files(paths: list[str], recursive: bool) list[str]

Expand a mix of .sv/.v files and directories into a deduplicated file list.

Directories are searched for *.sv and *.v files; when recursive is True the search descends into subdirectories (**/). Duplicate paths (by resolved canonical path) are silently dropped. Paths that are neither a file nor a directory emit a warning to stderr and are skipped.

svhier.cli.collect_inc_dirs(paths: list[str], recursive: bool) list[str]

Return directories that contain .svh/.vh header files under paths.

The result is written as +incdir+<dir> lines at the top of the generated filelist, which is the format expected by VCS, Questa, and Xcelium.

For directory inputs the search respects the recursive flag. For explicit file inputs the parent directory is checked for headers. Directories are returned in discovery order, deduplicated.

svhier.cli.main()

Entry point: parse arguments, run slang elaboration, emit YAML and optional filelist.

All Rich diagnostics (spinner, summary table, warnings) go to stderr so stdout stays clean for piped data. Exits with code 1 if pyslang reports any error-level diagnostics.

Filtering rules

The following symbols are intentionally excluded from the output:

  • Packages and interfacesgetDefinitions() is filtered to DefinitionKind.Module only.

  • Interface instances — excluded inside module bodies via the child.isModule guard (interface instances share SymbolKind.Instance with module instances but have isModule == False).

  • pkgs key — internal bookkeeping stripped from YAML output by _prepare_for_yaml().

  • diagnostics key — pyslang diagnostics are printed to stderr and stripped from YAML output.

Development notes

Warning

pyslang exposes its API through a compiled C++ extension that pylint cannot introspect. generated-members = ["pyslang.*"] in pyproject.toml suppresses the resulting false-positive no-member errors. The same list is passed to Sphinx via autodoc_mock_imports so the docs build without a compiled extension present.

Line length is set to 160 in the pylint configuration.