Exporter Module#
The Pybind11Exporter turns a SystemRDL
compilation into a buildable PyBind11 module. It can be driven directly from
Python or via the peakrdl pybind11 subcommand registered by the
peakrdl.exporters entry point.
Programmatic API#
The exporter is a plain class. Compile your RDL with the upstream
systemrdl-compiler, then hand the root node to Pybind11Exporter.export():
from systemrdl import RDLCompiler
from peakrdl_pybind11 import Pybind11Exporter
rdlc = RDLCompiler()
# Optional: pre-register the exporter's UDPs so users do not have to
# declare ``property is_flag {...}`` etc. in their RDL.
Pybind11Exporter.register_udps(rdlc)
rdlc.compile_file("mychip.rdl")
root = rdlc.elaborate()
Pybind11Exporter().export(
root,
output_dir="build/mychip",
soc_name="mychip",
split_by_hierarchy=True,
)
CLI options reference#
The exporter is exposed through peakrdl pybind11. peakrdl-cli itself
contributes the input file argument and --top; the flags below are the
ones added (or aspired to) by this exporter.
--soc-name NAMEName of the generated SoC module. Defaults to the top-level addrmap’s instance name. The chosen name shapes the import path your test code uses (
import NAME->NAME.create()).--top NODE(provided by peakrdl-cli.) Pick a non-root addrmap to export. Useful when one
.rdldefines several SoCs and you want bindings for just one.--gen-pyi/--no-gen-pyiEmit
.pyistub files alongside the compiled extension so editors and type checkers see the full hierarchy. Default: enabled.--split-bindings COUNTSplit the generated PyBind11 sources across multiple translation units when the register count exceeds COUNT. Speeds up compilation for large designs by enabling parallel
make/ninjajobs. Set to0to force a single TU. Default:100. Ignored when--split-by-hierarchyis used.--split-by-hierarchySplit bindings by addrmap/regfile boundary instead of by register count. Keeps related registers in the same translation unit, which is friendlier to incremental rebuilds and matches the way most large SoCs are organized.
--exploreSpawn an IPython REPL with
socalready created and ready to use. Inside the REPL,?soc.uart.controlshows full metadata and??soc.uart.controlshows the originating RDL source (sketch §21).--diff snapA snapBRender a text or HTML diff of two saved snapshots. Pairs with
soc.snapshot()andsoc.save()/soc.load()for golden-state regression workflows (sketch §21).--replay session.jsonReplay a recorded master session (the trace
Master.record()produces) against a target. Useful for reproducing a bug captured on silicon against a mock or a cosim model (sketch §21).--watch input.rdlRe-build and re-load the bound module whenever the input
.rdlchanges. Backed bywatchdog; emits a warning on every reload so you cannot miss it (sketch §21). See Hot reload semantics below.--strict-fields=falseBuild-time opt-out from the strict-fields default. Restores attribute-assign-as-read-modify-write so teams porting C drivers can keep their existing call sites (sketch §22.8).
Warning
--strict-fields=falseis intentionally noisy. It emits aDeprecationWarningonce at module import and once per loose attribute assignment. Silent RMW is the leading source of “I thought that wrote” bugs, and the warning stream is the price of the escape hatch. The strict default is preferred — useRegister.write_fields()orRegisterValue.replace()for multi-field updates.
Hot reload semantics#
--watch (and its in-process twin Soc.reload()) is opt-in. On
reload, the runtime:
emits a warning so the event is never silent,
invalidates outstanding
RegisterValueandSnapshothandles — they raise on next access rather than returning stale data,refuses to swap if a context manager (transaction, write-only block, etc.) is currently active, and
re-attaches the existing master to the freshly built tree.
Hardware bus state is not affected — only the host-side bindings are
replaced. Users who would rather crash than warn can set
peakrdl.reload.policy = "fail" and the runtime aborts the reload
instead of continuing with new bindings.
API reference#
Main exporter implementation for PeakRDL-pybind11
- class peakrdl_pybind11.exporter.Nodes[source]#
Bases:
TypedDict- addrmaps: list[AddrmapNode]#
- regfiles: list[RegfileNode]#
- signals: list[SignalNode]#
- class peakrdl_pybind11.exporter.Pybind11Exporter[source]#
Bases:
objectExport SystemRDL register descriptions to PyBind11 C++ modules
- top_node: AddrmapNode | None#
- export(top_node, output_dir, soc_name=None, soc_version='0.1.0', gen_pyi=True, split_bindings=100, split_by_hierarchy=False, interrupt_pattern=None)[source]#
Export SystemRDL to PyBind11 modules
- Parameters:
top_node (
RootNode|AddrmapNode) – Root node of the SystemRDL compilationoutput_dir (
str) – Directory to write output filessoc_name (
str|None) – Name of the SoC module (default: derived from top node)soc_version (
str) – Version string for the SoC module (default: “0.1.0”)gen_pyi (
bool) – Generate .pyi stub files for type hintssplit_bindings (
int) – Split bindings into multiple files when register count exceeds this threshold. Set to 0 to disable splitting. Default: 100 Ignored when split_by_hierarchy is True.split_by_hierarchy (
bool) – When True, split bindings by addrmap/regfile hierarchy instead of by register count. This keeps related registers together and provides more logical grouping. Default: Falseinterrupt_pattern (
object|None) – Optional override for the interrupt-state-register matcher used by the feature_detection exporter plugin. Accepts a regex string, compiledre.Pattern, or a callable(name: str) -> bool.
- Return type:
- classmethod register_udps(rdl_compiler)[source]#
Register every UDP this exporter recognizes with the given compiler.
For programmatic use:
from systemrdl import RDLCompiler from peakrdl_pybind11 import Pybind11Exporter
rdl = RDLCompiler() Pybind11Exporter.register_udps(rdl) rdl.compile_file(…)
CLI users can equivalently declare the UDPs in their RDL.