# PeakRDL-pybind11
[](https://github.com/arnavsacheti/PeakRDL-pybind11/blob/main/LICENSE)
[](https://peakrdl-pybind11.readthedocs.io/en/latest/?badge=latest)
PeakRDL-pybind11 is an exporter for the PeakRDL toolchain that generates PyBind11 modules from SystemRDL register descriptions. This enables Python-based hardware testing and interaction with register maps through a clean, type-safe Python API.
## Features
- **PyBind11 Module Generation**: Automatically generates C++ descriptors and Python bindings from SystemRDL
- **SoC Hierarchy Exposure**: Import generated modules to access the complete SoC register hierarchy
- **Pluggable Master Backends**: Support for multiple communication backends:
- Mock Master (for testing without hardware)
- OpenOCD Master (for JTAG/SWD debugging)
- SSH Master (for remote access)
- Custom Master backends (extensible interface)
- **Comprehensive API**:
- `attach_master()`: Connect to hardware or simulator
- `read()`: Read register values
- `write()`: Write register values
- `modify()`: Read-modify-write operations
- **Context Manager Support**: Batch field modifications for efficient register updates
- **Type Safety**: Generated `.pyi` stub files for full IDE support and type checking
- **Python-Based Testing**: Enable hardware testing with callbacks and custom logic
## Context Manager Support
The context manager feature allows you to batch multiple field modifications into a single bus transaction, significantly improving performance when updating multiple fields in the same register:
```python
# Traditional approach: Each field write is a separate read-modify-write cycle (6 bus transactions)
soc.uart.control.enable.write(1) # Read + Write
soc.uart.control.baudrate.write(2) # Read + Write
soc.uart.control.parity.write(1) # Read + Write
# Context manager approach: All modifications batched into one transaction (2 bus transactions)
with soc.uart.control as reg:
reg.enable.write(1) # Cached
reg.baudrate.write(2) # Cached
reg.parity.write(1) # Cached
# All changes written atomically when exiting context
# You can also read and manipulate field values within the context
with soc.uart.control as reg:
current_mode = reg.mode.read()
reg.enable.write(current_mode & 0x1)
reg.baudrate.write(2)
```
Benefits:
- **Performance**: Reduces bus transactions from N read + N write to 1 read + 1 write
- **Atomicity**: All field changes are committed together
- **Readability**: Cleaner code for complex field manipulations
## Installation
```bash
pip install peakrdl-pybind11
```
## Usage
### Command Line
```bash
peakrdl pybind11 input.rdl -o output_dir --soc-name MySoC --top top_addrmap --gen-pyi
```
#### CLI Options
- `--soc-name`: Name of the generated SoC module (default: derived from input file)
- `--top`: Top-level address map node to export (default: top-level node)
- `--gen-pyi`: Generate `.pyi` stub files for type hints (enabled by default)
- `--split-bindings COUNT`: Split bindings into multiple files for parallel compilation when register count exceeds COUNT. This significantly speeds up compilation for large register maps (default: 100, set to 0 to disable). Ignored when `--split-by-hierarchy` is used.
- `--split-by-hierarchy`: Split bindings by addrmap/regfile hierarchy instead of by register count. This keeps related registers together and provides more logical grouping. Recommended for designs with clear hierarchical structure.
#### Compilation Performance Optimization
For large register maps, compilation can be very slow. PeakRDL-pybind11 includes several optimizations:
1. **Hierarchical binding splitting** (recommended): Use `--split-by-hierarchy` to split bindings by addrmap/regfile boundaries. This keeps related registers together in the same compilation unit, providing better organization and cache locality.
2. **Register count binding splitting**: When register count exceeds `--split-bindings` threshold (default: 100), bindings are automatically split into multiple `.cpp` files that can be compiled in parallel
3. **Optimized compiler flags**: The generated CMakeLists.txt uses `-O1` optimization even for debug builds, which significantly reduces compilation time for template-heavy code
4. **Parallel compilation**: CMake will automatically compile split files in parallel when using `make -j` or `ninja`
Examples for large register maps:
```bash
# Split by hierarchy (recommended for well-structured designs)
peakrdl pybind11 large_design.rdl -o output --split-by-hierarchy
# Split bindings every 50 registers for faster compilation
peakrdl pybind11 large_design.rdl -o output --split-bindings 50
# Build with parallel compilation (4 cores)
cd output
pip install . -- -DCMAKE_BUILD_PARALLEL_LEVEL=4
```
### Python API
```python
from peakrdl_pybind11 import Pybind11Exporter
from systemrdl import RDLCompiler
# Compile SystemRDL
rdl = RDLCompiler()
rdl.compile_file("input.rdl")
root = rdl.elaborate()
# Export to PyBind11
exporter = Pybind11Exporter()
exporter.export(root, "output_dir", soc_name="MySoC")
# For large designs, enable binding splitting by hierarchy (recommended)
exporter.export(root, "output_dir", soc_name="MySoC", split_by_hierarchy=True)
# Or split by register count
exporter.export(root, "output_dir", soc_name="MySoC", split_bindings=50)
```
### Using Generated Modules
```python
import MySoC
from peakrdl_pybind11.masters import MockMaster
# Create and attach a master
soc = MySoC.create()
mock = MockMaster()
master = MySoC.wrap_master(mock)
soc.attach_master(master)
# Read/write registers
value = soc.peripherals.uart.control.read()
soc.peripherals.uart.control.write(0x1234)
# Access individual fields
soc.peripherals.uart.control.enable.write(1)
enable_value = soc.peripherals.uart.control.enable.read()
# Modify specific fields (traditional approach - each field modification is a separate bus transaction)
soc.peripherals.uart.control.enable.write(1)
soc.peripherals.uart.control.baudrate.write(2)
soc.peripherals.uart.control.parity.write(1)
# Use context manager for batched field modifications (recommended)
# Only 1 read + 1 write transaction to the bus
with soc.peripherals.uart.control as reg:
reg.enable.write(1)
reg.baudrate.write(2)
reg.parity.write(1)
# All changes are cached and written atomically when exiting the context
# Copy and modify field values within a context
with soc.peripherals.uart.control as reg:
current_baudrate = reg.baudrate.read()
reg.enable.write(current_baudrate & 0x1) # Use one field value to set another
```
## Requirements
- Python >= 3.10
- systemrdl-compiler >= 1.30.1
- jinja2
- CMake >= 3.15 (for building generated modules)
- C++11 compatible compiler (for building generated modules)
- pybind11 (runtime dependency for generated code)
## Benchmarks
Performance benchmarks are available to measure export and build times:
```bash
# Run fast export benchmarks
python benchmarks/run_benchmarks.py fast
# Run all benchmarks
pytest benchmarks/ --benchmark-only
# See all benchmark options
python benchmarks/run_benchmarks.py
```
See [benchmarks/README.md](benchmarks/README.md) for detailed documentation.
## Documentation
Full documentation is available at [ReadTheDocs](https://peakrdl-pybind11.readthedocs.io/).
To build the documentation locally:
```bash
pip install -e .[docs]
cd docs
make html
```
The built documentation will be in `docs/_build/html/`.
## License
This project is licensed under the GPL-3.0 License - see the [LICENSE](LICENSE) file for details.
Raw data
{
"_id": null,
"home_page": null,
"name": "peakrdl-pybind11",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "SystemRDL, PyBind11, register, hardware, testing",
"author": "Arnav Sacheti",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/e7/73/42a53af5990e50952848fcec210bf240259f9518f021f40533e370a2a497/peakrdl_pybind11-0.4.3.tar.gz",
"platform": null,
"description": "# PeakRDL-pybind11\n\n[](https://github.com/arnavsacheti/PeakRDL-pybind11/blob/main/LICENSE)\n[](https://peakrdl-pybind11.readthedocs.io/en/latest/?badge=latest)\n\nPeakRDL-pybind11 is an exporter for the PeakRDL toolchain that generates PyBind11 modules from SystemRDL register descriptions. This enables Python-based hardware testing and interaction with register maps through a clean, type-safe Python API.\n\n## Features\n\n- **PyBind11 Module Generation**: Automatically generates C++ descriptors and Python bindings from SystemRDL\n- **SoC Hierarchy Exposure**: Import generated modules to access the complete SoC register hierarchy\n- **Pluggable Master Backends**: Support for multiple communication backends:\n - Mock Master (for testing without hardware)\n - OpenOCD Master (for JTAG/SWD debugging)\n - SSH Master (for remote access)\n - Custom Master backends (extensible interface)\n- **Comprehensive API**: \n - `attach_master()`: Connect to hardware or simulator\n - `read()`: Read register values\n - `write()`: Write register values\n - `modify()`: Read-modify-write operations\n - **Context Manager Support**: Batch field modifications for efficient register updates\n- **Type Safety**: Generated `.pyi` stub files for full IDE support and type checking\n- **Python-Based Testing**: Enable hardware testing with callbacks and custom logic\n\n## Context Manager Support\n\nThe context manager feature allows you to batch multiple field modifications into a single bus transaction, significantly improving performance when updating multiple fields in the same register:\n\n```python\n# Traditional approach: Each field write is a separate read-modify-write cycle (6 bus transactions)\nsoc.uart.control.enable.write(1) # Read + Write\nsoc.uart.control.baudrate.write(2) # Read + Write\nsoc.uart.control.parity.write(1) # Read + Write\n\n# Context manager approach: All modifications batched into one transaction (2 bus transactions)\nwith soc.uart.control as reg:\n reg.enable.write(1) # Cached\n reg.baudrate.write(2) # Cached\n reg.parity.write(1) # Cached\n # All changes written atomically when exiting context\n\n# You can also read and manipulate field values within the context\nwith soc.uart.control as reg:\n current_mode = reg.mode.read()\n reg.enable.write(current_mode & 0x1)\n reg.baudrate.write(2)\n```\n\nBenefits:\n- **Performance**: Reduces bus transactions from N read + N write to 1 read + 1 write\n- **Atomicity**: All field changes are committed together\n- **Readability**: Cleaner code for complex field manipulations\n\n## Installation\n\n```bash\npip install peakrdl-pybind11\n```\n\n## Usage\n\n### Command Line\n\n```bash\npeakrdl pybind11 input.rdl -o output_dir --soc-name MySoC --top top_addrmap --gen-pyi\n```\n\n#### CLI Options\n\n- `--soc-name`: Name of the generated SoC module (default: derived from input file)\n- `--top`: Top-level address map node to export (default: top-level node)\n- `--gen-pyi`: Generate `.pyi` stub files for type hints (enabled by default)\n- `--split-bindings COUNT`: Split bindings into multiple files for parallel compilation when register count exceeds COUNT. This significantly speeds up compilation for large register maps (default: 100, set to 0 to disable). Ignored when `--split-by-hierarchy` is used.\n- `--split-by-hierarchy`: Split bindings by addrmap/regfile hierarchy instead of by register count. This keeps related registers together and provides more logical grouping. Recommended for designs with clear hierarchical structure.\n\n#### Compilation Performance Optimization\n\nFor large register maps, compilation can be very slow. PeakRDL-pybind11 includes several optimizations:\n\n1. **Hierarchical binding splitting** (recommended): Use `--split-by-hierarchy` to split bindings by addrmap/regfile boundaries. This keeps related registers together in the same compilation unit, providing better organization and cache locality.\n2. **Register count binding splitting**: When register count exceeds `--split-bindings` threshold (default: 100), bindings are automatically split into multiple `.cpp` files that can be compiled in parallel\n3. **Optimized compiler flags**: The generated CMakeLists.txt uses `-O1` optimization even for debug builds, which significantly reduces compilation time for template-heavy code\n4. **Parallel compilation**: CMake will automatically compile split files in parallel when using `make -j` or `ninja`\n\nExamples for large register maps:\n```bash\n# Split by hierarchy (recommended for well-structured designs)\npeakrdl pybind11 large_design.rdl -o output --split-by-hierarchy\n\n# Split bindings every 50 registers for faster compilation\npeakrdl pybind11 large_design.rdl -o output --split-bindings 50\n\n# Build with parallel compilation (4 cores)\ncd output\npip install . -- -DCMAKE_BUILD_PARALLEL_LEVEL=4\n```\n\n### Python API\n\n```python\nfrom peakrdl_pybind11 import Pybind11Exporter\nfrom systemrdl import RDLCompiler\n\n# Compile SystemRDL\nrdl = RDLCompiler()\nrdl.compile_file(\"input.rdl\")\nroot = rdl.elaborate()\n\n# Export to PyBind11\nexporter = Pybind11Exporter()\nexporter.export(root, \"output_dir\", soc_name=\"MySoC\")\n\n# For large designs, enable binding splitting by hierarchy (recommended)\nexporter.export(root, \"output_dir\", soc_name=\"MySoC\", split_by_hierarchy=True)\n\n# Or split by register count\nexporter.export(root, \"output_dir\", soc_name=\"MySoC\", split_bindings=50)\n```\n\n### Using Generated Modules\n\n```python\nimport MySoC\nfrom peakrdl_pybind11.masters import MockMaster\n\n# Create and attach a master\nsoc = MySoC.create()\nmock = MockMaster()\nmaster = MySoC.wrap_master(mock)\nsoc.attach_master(master)\n\n# Read/write registers\nvalue = soc.peripherals.uart.control.read()\nsoc.peripherals.uart.control.write(0x1234)\n\n# Access individual fields\nsoc.peripherals.uart.control.enable.write(1)\nenable_value = soc.peripherals.uart.control.enable.read()\n\n# Modify specific fields (traditional approach - each field modification is a separate bus transaction)\nsoc.peripherals.uart.control.enable.write(1)\nsoc.peripherals.uart.control.baudrate.write(2)\nsoc.peripherals.uart.control.parity.write(1)\n\n# Use context manager for batched field modifications (recommended)\n# Only 1 read + 1 write transaction to the bus\nwith soc.peripherals.uart.control as reg:\n reg.enable.write(1)\n reg.baudrate.write(2)\n reg.parity.write(1)\n # All changes are cached and written atomically when exiting the context\n\n# Copy and modify field values within a context\nwith soc.peripherals.uart.control as reg:\n current_baudrate = reg.baudrate.read()\n reg.enable.write(current_baudrate & 0x1) # Use one field value to set another\n```\n\n## Requirements\n\n- Python >= 3.10\n- systemrdl-compiler >= 1.30.1\n- jinja2\n- CMake >= 3.15 (for building generated modules)\n- C++11 compatible compiler (for building generated modules)\n- pybind11 (runtime dependency for generated code)\n\n## Benchmarks\n\nPerformance benchmarks are available to measure export and build times:\n\n```bash\n# Run fast export benchmarks\npython benchmarks/run_benchmarks.py fast\n\n# Run all benchmarks\npytest benchmarks/ --benchmark-only\n\n# See all benchmark options\npython benchmarks/run_benchmarks.py\n```\n\nSee [benchmarks/README.md](benchmarks/README.md) for detailed documentation.\n## Documentation\n\nFull documentation is available at [ReadTheDocs](https://peakrdl-pybind11.readthedocs.io/).\n\nTo build the documentation locally:\n\n```bash\npip install -e .[docs]\ncd docs\nmake html\n```\n\nThe built documentation will be in `docs/_build/html/`.\n\n## License\n\nThis project is licensed under the GPL-3.0 License - see the [LICENSE](LICENSE) file for details.\n",
"bugtrack_url": null,
"license": "GPL-3.0-only",
"summary": "Export SystemRDL to PyBind11 modules for Python-based hardware testing",
"version": "0.4.3",
"project_urls": {
"Homepage": "https://github.com/arnavsacheti/PeakRDL-pybind11",
"Issues": "https://github.com/arnavsacheti/PeakRDL-pybind11/issues",
"Repository": "https://github.com/arnavsacheti/PeakRDL-pybind11"
},
"split_keywords": [
"systemrdl",
" pybind11",
" register",
" hardware",
" testing"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "0de8c48e320a17323212603c859b4156b65efcafbe7b6b6302d96d12341962b4",
"md5": "1fc59c6e60d2824a3915642eb7fc78be",
"sha256": "7de70086193319c159d263ca5787d5833bea42503fd8050d08e21efcf2ac65f2"
},
"downloads": -1,
"filename": "peakrdl_pybind11-0.4.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "1fc59c6e60d2824a3915642eb7fc78be",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 42377,
"upload_time": "2025-10-31T05:03:04",
"upload_time_iso_8601": "2025-10-31T05:03:04.282381Z",
"url": "https://files.pythonhosted.org/packages/0d/e8/c48e320a17323212603c859b4156b65efcafbe7b6b6302d96d12341962b4/peakrdl_pybind11-0.4.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "e77342a53af5990e50952848fcec210bf240259f9518f021f40533e370a2a497",
"md5": "29225fa2179afc4be83224ef79aa3b42",
"sha256": "62c5081baaae5576b90547a26f1ea1059be1615c893a4171afe745111cbedd5d"
},
"downloads": -1,
"filename": "peakrdl_pybind11-0.4.3.tar.gz",
"has_sig": false,
"md5_digest": "29225fa2179afc4be83224ef79aa3b42",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 49446,
"upload_time": "2025-10-31T05:03:05",
"upload_time_iso_8601": "2025-10-31T05:03:05.698345Z",
"url": "https://files.pythonhosted.org/packages/e7/73/42a53af5990e50952848fcec210bf240259f9518f021f40533e370a2a497/peakrdl_pybind11-0.4.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-31 05:03:05",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "arnavsacheti",
"github_project": "PeakRDL-pybind11",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "peakrdl-pybind11"
}