Developer guide
Environment
To setup a local build configuration, for example if you are using VSCode's CMake integration, create a CMake user preset that in CMakeUserPresets.json in the root directory of the project. This user preset can inherit from one of the standard ones in CMakePresets.json and add its own variables. For example:
{
"version": 3,
"configurePresets": [
{
"name": "macos-local",
"displayName": "macOS local",
"generator": "Ninja",
"inherits": [
"macos-debug"
],
"cacheVariables": {
"CMAKE_PREFIX_PATH": "/Users/jamie/llvm-project/install/bin",
"CMAKE_BUILD_TYPE": "Debug",
"ENABLE_PY_BINDINGS": ON,
"CODE_COVERAGE": "OFF",
"BUILD_DOCS": "OFF"
}
}
]
}Then to use this preset:
cmake --preset macos-local cmake --build build/macos-local --target install ctest --test-dir build/macos-local --output-on-failure --no-tests=error
Report code coverage:
# Compile with -DCODE_COVERAGE=ON, then: make ccov-run-netlist_unittests make ccov-report
Profile performance using cachegrind:
valgrind --tool=cachegrind netlist_unittests # Analyse results in speedscope.
To build the documentation install the Python dependenices:
virtualenv venv source venv/bin/activate pip install requirements.txt # Compile with -DBUILD_DOCS=ON
External tests
The test suite includes tests using code from external projects, enabled with -DENABLE_EXTERNAL_TESTS=ON (this is the default).
RTLmeter** is a collection of large reference designs (BlackParrot, Caliptra, NVDLA, OpenPiton, OpenTitan, VeeR, Vortex, XiangShan, XuanTie) sourced from verilator/
ctest --test-dir build/macos-local -R rtlmeter-tests --output-on-failure
The RTLmeter suite runs one unittest per design; failures print the slang-netlist stderr so the root cause is visible directly in the test output. Each design has a 5-minute timeout and the overall test has a 1-hour timeout. Because these are large, real-world designs, some may fail due to slang-netlist limitations and are useful for tracking coverage progress.
To skip the external tests entirely (e.g. for faster iteration):
cmake --preset macos-local -DINCLUDE_EXTERNAL_TESTS=OFF
Architecture
The library builds a directed dependency graph (the "netlist") over an elaborated SystemVerilog AST provided by slang. The graph captures source-level static connectivity at bit-level granularity. The main components are described below.
Graph data structures
The graph is built on a generic DirectedGraph<NodeType,EdgeType> template that stores nodes in an adjacency list and edges as shared pointers on each node. The netlist specialises this as NetlistGraph, holding NetlistNode and NetlistEdge objects.
NetlistNode is a polymorphic base with a NodeKind discriminator. Concrete subtypes are:
Port— an input or output port of a module instance.Variable— a net or variable declaration.State— a register (variable driven inside a clocked procedural block).Assignment— a continuous or procedural assignment expression.Conditional/Case— an if or case branch in a procedural block.Merge— a synthetic join point that merges two branches back together.
NetlistEdge carries annotations for the driven symbol, its bit range, and an ast::EdgeKind that records clock sensitivity (used to distinguish combinational from sequential edges).
Graph construction
NetlistBuilder is the main AST visitor (slang::ast::ASTVisitor). Construction is a two-phase process:
- Elaboration: A
VisitAllpass forces full lazy construction of the AST. The compilation is then frozen (Compilation::freeze()), making the AST safe for concurrent reads. - Netlist population:
NetlistBuildertraverses the AST and creates graph nodes for ports, variables, and instances. For each procedural block (always,initial) and continuous assignment it runs a localDataFlowAnalysis, which extends slang'sAbstractFlowAnalysisto model if/case branching, static loop unrolling, and non-blocking assignments. The analysis produces per-symbol driver maps that are merged into the centralValueTracker.
After the traversal, NetlistBuilder::finalize() resolves deferred R-value connections (operands that depend on all drivers being present first).
Key supporting types:
ValueTracker/VariableTracker— interval-map-based structures that track which netlist nodes drive which bit ranges of each symbol.DriverMap— a thin wrapper around slang'sIntervalMap, mapping bit ranges to driver lists.ExternalManager<T>— a handle-based allocator used becauseIntervalMapvalues must be trivially copyable.
Multithreading
Phase 2 of netlist construction is parallelised using a BS::deferredBlocks work list. In Phase 2 each deferred block is dispatched as an independent task to the thread pool, where it runs its own DataFlowAnalysis and merges results back into the shared graph.
Thread safety is achieved through several mechanisms:
- The slang AST is frozen (
Compilation::freeze()) before Phase 2, making it safe for concurrent reads. NetlistGraph::addNode()andNetlistGraph::addEdge()are protected by a mutex so that graph mutations from different tasks do not race.- The pending R-value list is guarded by
pendingRValuesMutex. NetlistNodeIDs are allocated with an atomic counter.
Analysis and queries
PathFinder— finds a path between two nodes using depth-first search; returns aNetlistPath.CombLoops/CycleDetector— detects combinational loops by only traversing edges without clock sensitivity (EdgeKind::None).DepthFirstSearch— generic DFS template parameterised on a visitor and an edge predicate; used by bothPathFinderandCycleDetector.
Tooling
tools/driver/driver.cpp— theslang-netlistCLI binary. It links against thenetlistlibrary and exposes commands such as--report-registers,--comb-loops,--from/queries, and--topath--netlist-dotgraph export.bindings/python/pyslang_netlist.cpp— pybind11 Python module (pyslang_netlist); enabled with-DENABLE_PY_BINDINGS=ON.
Dependencies
All fetched automatically via CPM at configure time:
Pre commit
Pre-commit runs a set of lint checks on files when creating git commits, with the config in .pre-commit.
You can install the hooks explicity with:
pre-commit install
And you can run pre-commit checks on all files with:
pre-commit run -a
To update the verisons of the hooks used in the pre-commit configuration file:
pre-commit autoupdate
Ubuntu Docker environment
You can use Docker to create an Ubuntu development environment, eg:
docker build -t slang-netlist-dev docker/ubuntu docker run -it slang-netlist-dev
This is useful to debug issues seen in CI, especially when developing on MacOS.