Wolvrix parses SystemVerilog into GRH (Graph RTL Hierarchy), runs transform passes on that IR, and writes results back out through emitters and storage backends.
Today, the main way to use Wolvrix is the Python API.
The Python API is organized around a single Session object. Instead of passing standalone Design objects around in Python, you keep your working state inside the session:
- read or load a design into a session key
- run passes against that design key
- write extra results into other session keys when needed
- emit or store files from the same session
This model keeps design data, intermediate pass results, diagnostics, and debugging state in one place.
git submodule update --init --recursive
cmake -S wolvrix -B wolvrix/build
cmake --build wolvrix/build -j$(nproc)Install the Python package:
python3 -m pip install --no-build-isolation -e .import wolvrix
with wolvrix.Session() as sess:
sess.log_level = "info"
sess.diagnostics_print_min_level = "warning"
sess.diagnostics_raise_min_level = "error"
sess.read_sv(
"path/to/top.sv",
out_design="design.main",
slang_args=["--top", "top"],
)
sess.run_pass("xmr-resolve", design="design.main")
sess.run_pass("simplify", design="design.main")
sess.run_pass("stats", design="design.main", out_stats="stats.main")
sess.store_json(design="design.main", output="build/main.json")
sess.emit_sv(design="design.main", output="build/main.sv")What happens in this example:
read_sv(...)creates a design and stores it underdesign.main.- Each
run_pass(...)call modifiesdesign.mainin place. out_stats="stats.main"stores a separate result in the same session.store_json(...)andemit_sv(...)write files using the design stored in the session.
The naming rules are intentionally simple:
- use
out_design=...when an action creates or loads a design - use
design=...for the design being operated on - use
in_*andout_*for session-based data flow - use regular keyword arguments for ordinary pass or emit configuration
Example:
with wolvrix.Session() as sess:
sess.read_sv("top.sv", out_design="design.main")
sess.run_pass("stats", design="design.main", out_stats="stats.main")This reads naturally:
design="design.main"tells you which design is being worked onout_stats=...tells you which additional session value will be produced
Every action returns diagnostics as list[dict].
diags = sess.run_pass("stats", design="design.main", out_stats="stats.main")Logging is separate from diagnostics:
- diagnostics are structured results returned to Python
- logs are C++ runtime messages printed directly from native code
Configure them at the session level:
with wolvrix.Session() as sess:
sess.diagnostics_print_min_level = "warning" # none | warning | error
sess.diagnostics_raise_min_level = "error" # none | warning | error
sess.log_level = "warn" # trace | debug | info | warn | error | offDefault behavior is usually enough:
- warning and error diagnostics are printed automatically
- error diagnostics raise automatically
- every action still returns the diagnostics list for explicit inspection
Useful helpers:
text = wolvrix.format_diagnostics(diags, min_level="info")
wolvrix.print_diagnostics(diags, min_level="warning")The session is a key-value store.
Common keys look like this:
design.maindesign.flatstats.mainloops.main
You can inspect the session with:
value = sess.get("stats.main")
kind = sess.kind("stats.main")
keys = sess.keys(prefix="stats.")Not every session value needs a rich Python representation.
- if a
kindhas a Python adapter,sess.get(...)returns that adapter object - otherwise it returns
OpaqueValue
This is deliberate. Session values are not only for Python debugging; they are also how C++ passes and emitters pass data to each other.
Currently implemented:
sess.store_json(*, design: str, output: str, mode="pretty-compact", top=None)
sess.emit_sv(*, design: str, output: str, top=None, split_modules=False)
sess.emit_verilator_repcut_package(*, design: str, output: str, top=None)These emitters do not yet consume extra session values, so they currently expose no in_* parameters. If you pass an unsupported in_*, the API raises an error instead of silently ignoring it.
If you are new to Wolvrix, read these in order:
ctest --test-dir wolvrix/build --output-on-failure