RTL hierarchy and connectivity visualization tool. Pluggable Verible (source CST) or slang (elaborated) frontend; renders Graphviz / ASCII / Mermaid / JSON; integrates with rtl-buddy.
Project description
rtl-buddy-view
RTL hierarchy and connectivity visualization. Pluggable parser
frontend (Verible for
source-faithful CST, slang
via pyslang for elaborated views
of generates / parameterized instances) → in-memory hierarchy graph →
four renderers (ASCII tree, Graphviz .dot, Mermaid, JSON). With an
optional clock-domain map from rtl-buddy-cdc,
every renderer overlays clock-domain context and flags asynchronous
CDC crossings inline. Integrated into rtl-buddy
as rb hier — the recommended entry point for users with a
models.yaml-backed project.
Why
Engineers reviewing an unfamiliar SystemVerilog design want a quick answer to "what instantiates what, with which parameters, and how their ports connect" — without firing up a commercial tool (Sigasi Visualizer, DVT) or paging through RTL by hand. The open-source EDA stack has strong synthesis (Yosys), simulation (Verilator, Icarus), and waveform viewing (Surfer, GTKWave) but no first-class source-level hierarchy browser.
This is not netlist visualization. Yosys show + netlistsvg
covers the gate-level case beautifully. rtl-buddy-view operates one
level up: on the source hierarchy, preserving comments, parameter
overrides, and source positions, so the rendered diagram is something
you can hand to an engineer (or an LLM) and have them navigate the
design from.
Architecture
SV sources + --top
│
▼
┌─────────────────┐
│ frontend │
│ ├─ verible │ verible-verilog-syntax --export_json
│ │ │ content-hashed CST cache (XDG)
│ └─ slang │ pyslang elaborate (Phase 2 fallback)
└────────┬────────┘
▼
┌─────────────────┐
│ extractor │ Module { name, ports, params, instances,
│ (CST → model) │ location } (frozen dataclasses)
└────────┬────────┘
▼
┌─────────────────┐
│ hierarchy graph │ build_hierarchy(table, top) → HierNode tree
│ │ unresolved children → blackbox leaves
└────────┬────────┘
│ ┌─ optional: rtl-buddy-cdc domain map
│ │ (annotations.load_domain_map)
▼ ▼
┌─────────────────────────────────┐
│ renderers │ query API │
│ tree / dot / │ walk, subtree,│
│ mermaid / json │ port_…, … │
└─────────────────────────────────┘
Same shape as rtl-buddy-cdc: pure analyzer at the core, frontend is a thin wrapper, source anchors carried through every layer.
Install
uv sync
# optional elaboration frontend
uv sync --extra slang
# fetch the pinned Verible binary into vendor/
uv run python scripts/fetch_verible.py
On macOS, brew install verible is also fine — the tool prefers a
PATH binary over the vendored copy.
Building the wheel with the Vue SPA shipped
The wheel includes a pre-built copy of the Vue 3 viewer SPA so
rtl_buddy's hub (rb hub start --serve-viewer) can discover it via
importlib.resources without the user passing --viewer-bundle. To
build a wheel locally:
uv run python scripts/prebuild_viewer.py # npm ci + npm run build + stage
uv build --wheel # produces dist/*.whl
The prebuild step copies viewer/dist/* to src/rtl_buddy_view/_viewer_bundle/
(gitignored) and filters out source maps. The Wheel CI workflow
runs the same two steps on every PR touching src/, viewer/, or
pyproject.toml, and fails if the published wheel doesn't contain
_viewer_bundle/index.html + a JS asset.
Programmatic access from downstream code:
from rtl_buddy_view import viewer_bundle
path = viewer_bundle.path() # Path | None
Returns None when iterating from a checkout without a staged
bundle — callers fall back to their own placeholder.
Use via rb hier
If your project already uses rtl-buddy,
the recommended entry point is rb hier <model> — it derives --top
and --filelist from the model declared in models.yaml, writes the
generated filelist to artefacts/hier/<model>/hier.f, and forwards
every renderer flag below. All examples in the Quickstart below
translate to rb hier <model> --format <fmt> once the model is
registered.
The wrapper lives at
tools/hier_rtl_buddy_view.py
in the rtl-buddy repo and reaches rtl-buddy-view via PATH. Install
this package into the same virtualenv so rb hier picks it up.
Quickstart
# ASCII tree — the fastest way to eyeball a design
uv run rtl-buddy-view \
--top counter_with_subs \
--filelist tests/fixtures/counter_with_subs/files.f \
--format tree
# Graphviz .dot, written to a file for piping through `dot -Tsvg`
uv run rtl-buddy-view \
--top counter_with_subs \
--filelist tests/fixtures/counter_with_subs/files.f \
--format dot --output hier.dot
dot -Tsvg hier.dot -o hier.svg
# Mermaid — paste straight into a GitHub PR or README
uv run rtl-buddy-view \
--top counter_with_subs \
--filelist tests/fixtures/counter_with_subs/files.f \
--format mermaid
# Machine-readable JSON (the format `rb hier` consumes)
uv run rtl-buddy-view \
--top counter_with_subs \
--filelist tests/fixtures/counter_with_subs/files.f \
--format json --output hier.json
Overlays — --overlay name=path
Every overlay (clock, reset, and the Phase 6+ coverage / physical / waveform ones) is dispatched through a single repeatable flag:
uv run rtl-buddy-view --list-overlays
# clock 1.0
# reset 1.0
uv run rtl-buddy-view \
--top top \
--filelist tests/fixtures/two_clock_two_reset_design/files.f \
--overlay clock=tests/fixtures/two_clock_two_reset_design/clock_map.json \
--overlay reset=tests/fixtures/two_clock_two_reset_design/reset_map.json \
--format tree
--list-overlays enumerates the registered overlay names + their
schema versions. Unknown overlay names surface the registered set
in the error message so typos self-correct. Third-party packages
register additional overlays via the
rtl_buddy_view.overlays entry-point group — see
docs/overlays.md for the protocol + a
worked example.
Deprecation note. The pre-Phase-4
--cdc-annotationsand--rdc-annotationsflags still work as aliases (with a deprecation warning each), rewriting internally to--overlay clock=…/--overlay reset=…. They'll be removed in the next major bump.
Clock-domain overlay (consuming --overlay clock=…)
When rtl-buddy-cdc has produced a --emit-domain-map JSON for the
same design, the clock overlay tints subtree nodes by their
clock domain, tags per-node labels, and marks asynchronous
crossings with ⚠CDC:
uv run rtl-buddy-view \
--top two_clock_design \
--filelist tests/fixtures/two_clock_design/files.f \
--overlay clock=tests/fixtures/two_clock_design/domain_map.json \
--format dot --clock-legend --output two_clock.dot
Without --overlay clock=… (or with an empty map), output is
byte-identical to the un-annotated case.
Reset-domain overlay (consuming --overlay reset=…)
When rtl-buddy-cdc has produced a --emit-reset-domain-map JSON for
the same design, the reset overlay adds per-flop reset
binding/polarity, reset-synchroniser markers, and ⚠RDC markers
on reset crossings. Composable with --overlay clock=…:
uv run rtl-buddy-view \
--top top \
--filelist tests/fixtures/two_clock_two_reset_design/files.f \
--overlay clock=tests/fixtures/two_clock_two_reset_design/clock_map.json \
--overlay reset=tests/fixtures/two_clock_two_reset_design/reset_map.json \
--format tree
Output:
top [clk_b]
├── u_rstgen : rstsync [clk_b]
│ └── u_sync : ff [clk_b] ✓rstsync
└── u_fifo : fifo [clk_a]
├── u_wr_ptr : ff [clk_a, rst_n↓]
└── u_rd_ptr : ff [clk_b, rst_n↓] ⚠RDC[rst_n:async-deassert]
Reset overlay surface, by renderer:
| Format | Reset binding | Synchronizer | RDC crossing |
|---|---|---|---|
tree |
[<reset>↓] (down for active-low, up for active-high) joined into the clock bracket |
✓rstsync after the bracket |
⚠RDC[reset:kind] suffix |
dot |
reset bracket line in node label | teal outline (#0d9488) + ✓rstsync line |
dashed-orange edge (#ea580c); dashed-orange arrow from top frame's reset-port anchor when applicable |
mermaid |
reset bracket line in node label | teal stroke + ✓rstsync line |
dashed arrow + orange stroke on destination |
json |
per-node reset object |
per-node is_reset_synchronizer: true |
per-node reset_crossings_in[] |
When CDC and RDC both apply to the same flop, CDC takes precedence on stroke / border colour (silicon-failing metastability is the more severe hazard), while the RDC marker rides on the label. The other warning still surfaces — nothing is hidden.
Without --rdc-annotations, no reset decoration is emitted; the
output is byte-identical to the clock-only / un-annotated case.
CLI
rtl-buddy-view [OPTIONS]
--top, -t TEXT Top module name. [required]
--filelist, -f PATH One source file per line; +incdir+/-y/-f rejected.
[required]
--format [tree|dot|mermaid|json]
Output format. [default: tree]
--output, -o PATH Write to file instead of stdout.
--frontend [verible|slang]
Parser frontend. [default: verible]
(slang activation is a Phase 2 follow-up.)
--overlay name=path Apply the named overlay. Repeatable.
Built-ins: clock, reset.
Examples: --overlay clock=clock-map.json
--overlay reset=reset-map.json
--list-overlays List registered overlays + their schema
versions and exit.
--cdc-annotations PATH (Deprecated; use --overlay clock=PATH.)
--rdc-annotations PATH (Deprecated; use --overlay reset=PATH.)
--clock-legend Dot-format only: emit a side legend mapping
clocks → palette colors. Requires a clock
overlay.
view.json v1 (--format json)
The JSON output is the locked v1 contract that the Phase 5 web
viewer (#18) and rb hier consume. Schema lives at
schemas/view-v1.json; the full field-by-field reference is in
docs/view-json-v1.md. Each node carries:
- a stable
id(full instance path),module,instance_name,is_blackbox,parametersdict, andports[]withexpr+anchorjoined from the parent instantiation; - a
sourceblock withdecl_line/decl_colfor the module declaration alongside the instance anchor; - a
linkURI of the formrtlbuddy://open?file=…&line=…&col=…(the hub in Phase 10b is the URI handler); - an
overlaysblock keyed by overlay name with per-node metadata.
overlays_present at the top level lists the active overlays so a
viewer can render its panel of toggles without scanning every node.
Tree output running on a real terminal also wraps each instance
name in an OSC-8 hyperlink pointing at the same rtlbuddy:// URI
— click-through into the hub straight from your terminal. Pipes /
redirects auto-disable OSC-8 so plain-text capture stays
machine-readable; NO_COLOR=1 is also respected.
Public API
A small surface is exported as a stable, SemVer-covered Python API for downstream rtl-buddy tools that need the same Verible-CST infrastructure (currently rtl-buddy-axi-profiler and the upcoming rtl-buddy-xeno; see view#109 for the promotion rationale). The contract:
| Symbol | Purpose |
|---|---|
rtl_buddy_view.frontend.verible.locate_binary |
Locate verible-verilog-syntax — PATH-first, vendored fallback |
rtl_buddy_view.cst_cache.get_or_compute |
Content-hashed CST cache; takes verible_binary, compute, cache_dir |
rtl_buddy_view.cst_cache.cache_root |
Cache-root path; takes optional override |
rtl_buddy_view.offsets.OffsetIndex |
Byte-offset → (line, column), UTF-8-correct, O(log n) |
rtl_buddy_view.extractor.SourceLocation |
Frozen (file, start_line, start_column, end_line, end_column) |
Plus the existing extractor dataclasses (Module, Port, Parameter, Instance) consumed via the JSON renderer's pinned contract.
Anything not in that list (graph internals, renderer internals, the SPA bundle path, the underscore-prefixed modules) is implementation detail and may change without notice. The legacy underscore-prefixed imports (rtl_buddy_view._cst_cache, rtl_buddy_view._offsets) remain available as deprecation shims for one minor version with a DeprecationWarning pointing at the new locations.
CST cache — shared across rtl-buddy tools
The cache directory is a shared resource across any rtl-buddy tool that imports cst_cache. Resolution order, decreasing precedence:
cache_dirkeyword argument toget_or_compute(caller-injected; the rtl_buddy orchestrator's preferred path — it readscfg-cst-cache.dirfromroot_config.yamland passes it through).RTL_BUDDY_CACHE_DIRenvironment variable.RTL_BUDDY_VIEW_CACHE_DIR(deprecated alias; emits aDeprecationWarning).$XDG_CACHE_HOME/rtl-buddy/sv-cst/(per the XDG Base Directory spec).~/.cache/rtl-buddy/sv-cst/(XDG default).
If only the legacy <xdg-cache>/rtl-buddy-view/cst/ directory exists on disk, it is read as a one-time fallback with a DeprecationWarning. New writes always go to the new path.
RTL_BUDDY_NO_CACHE=1 disables caching entirely (useful for CI and Verible-overhead measurement); RTL_BUDDY_VIEW_NO_CACHE is honoured as a deprecated alias.
Roadmap
- Phase 1 ✅ — Verible frontend, semantic extractor, hierarchy graph, ASCII tree + Graphviz renderers, query API. (#1)
- Phase 2 ✅ — Mermaid + JSON renderers, clock-domain overlay
consuming rtl-buddy-cdc's schema-v1.0 domain map, deterministic
output across all formats, JSON contract pinned for downstream
rb hier. (#2) - Phase 3 ✅ — Reset-domain overlay consuming rtl-buddy-cdc's schema-v1.0 reset-domain map: per-flop reset binding + polarity, reset-synchroniser markers, dashed-orange RDC edges, and combined-overlay rendering across all four output formats. (#3)
- Phase 4 — Generalised overlay plugin layer
(
--overlay name=path), lockedview.jsonv1 schema, OSC-8 hyperlinks in the tree renderer. (#17)
License
BSD 3-Clause. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rtl_buddy_view-0.2.1-py3-none-any.whl.
File metadata
- Download URL: rtl_buddy_view-0.2.1-py3-none-any.whl
- Upload date:
- Size: 727.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4db09ec7fbb2a0ae42e19c715ac36f62e9e99f8d7fd062007192c6fc506543bb
|
|
| MD5 |
b786723658f8faafa1d555083e9b91a0
|
|
| BLAKE2b-256 |
f96a28d289eb41185e835eae30f9d9c91d92cc89070eba5a126835229f6703fc
|
Provenance
The following attestation bundles were made for rtl_buddy_view-0.2.1-py3-none-any.whl:
Publisher:
release.yml on rtl-buddy/rtl-buddy-view
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rtl_buddy_view-0.2.1-py3-none-any.whl -
Subject digest:
4db09ec7fbb2a0ae42e19c715ac36f62e9e99f8d7fd062007192c6fc506543bb - Sigstore transparency entry: 1730505510
- Sigstore integration time:
-
Permalink:
rtl-buddy/rtl-buddy-view@0f37a432de34f667e2f1cb6681584ad7fd581415 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/rtl-buddy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0f37a432de34f667e2f1cb6681584ad7fd581415 -
Trigger Event:
pull_request
-
Statement type: