Architecture
============
System Architecture
-------------------
The Zuspec HDLSim backend implements a dual-domain architecture that partitions
verification logic between SystemVerilog (for hardware simulation) and Python
(for test orchestration).
.. mermaid::
graph TB
subgraph Python["Python Domain (pytest via PyHDL-IF)"]
PY1["• Test Orchestration"]
PY2["• Top-level Component"]
PY3["• Python-only Components"]
PY4["• Test Sequences & Scenarios"]
end
subgraph SV["SystemVerilog Domain (HDL Simulator)"]
SV1["• Generated Testbench Module"]
SV2["• Generated Transactors (XtorComponent)"]
SV3["• Extern Components (existing HDL)"]
SV4["• Signal-level Connectivity"]
SV5["• DUT (Design Under Test)"]
end
Python <-->|"PyHDL-IF Bridge
(TLM/API calls)"| SV
style Python fill:#e1f5ff
style SV fill:#ffe1f5
Component Classification
------------------------
The backend classifies components into three categories that determine their
implementation domain:
Extern Components
^^^^^^^^^^^^^^^^^
**Purpose**: Wrap existing SystemVerilog modules for use in Zuspec testbenches
**Implementation**: SystemVerilog only (pre-existing or provided by user)
**Characteristics**:
* Inherit from ``Extern`` protocol
* Reference existing HDL modules
* Provide SystemVerilog source filesets via ``@annotation_fileset``
* Connect to other SV components via signals/interfaces
**Example**:
.. code-block:: python
@zdc.dataclass
class DutWrapper(zdc.Component, Extern):
"""Wrapper for existing DUT module."""
@annotation_fileset(sources=["dut.sv"])
def __post_init__(self):
pass
XtorComponent Transactors
^^^^^^^^^^^^^^^^^^^^^^^^^^
**Purpose**: Define transactors that generate both SystemVerilog and Python APIs
**Implementation**: SystemVerilog (generated) + Python proxy (runtime)
**Characteristics**:
* Inherit from ``XtorComponent[Protocol]``
* Protocol defines the transaction API
* SV code generated by zuspec-be-sv
* Python API wrapper generated via `PyHDL-IF `_
* Connect via ``xtor_if`` interface
**Example**:
.. code-block:: python
@zdc.dataclass
class ClkGenXtor(XtorComponent[ClkGenIf]):
"""Clock generator transactor."""
clock: Signal = zdc.output()
async def start(self, freq_mhz: int):
"""Start clock generation."""
...
Python Components
^^^^^^^^^^^^^^^^^
**Purpose**: Pure Python verification components
**Implementation**: Python only
**Characteristics**:
* Standard Zuspec components
* No signal-level connectivity to SV domain
* Communicate via TLM/method calls
* Run in pytest environment
Domain Separation Rules
-----------------------
The HDLTestbench profile enforces strict domain separation:
1. **No Signal-Level Crossing**: Python components cannot connect directly to
signals in the SV domain
2. **TLM Boundary**: Communication between domains uses transaction-level
modeling (method calls on xtor_if)
3. **Extern Isolation**: Extern components can only connect to other SV
components (Extern or XtorComponent)
Generation Flow
---------------
Build Time (GenTB Task)
^^^^^^^^^^^^^^^^^^^^^^^^
.. mermaid::
flowchart TD
Start[Zuspec Component Class] --> Check[Profile Checking]
Check --> |Valid| SVGen[SV Generation]
Check --> |Errors| Fail[Report Errors]
SVGen --> Trans[Generate Transactor Modules
via zuspec-be-sv]
SVGen --> TBMod[Generate Testbench Wrapper Module]
SVGen --> API[Generate PyHDL-IF API Definitions JSON]
Trans --> APIGen[PyHDL-IF API Generation]
API --> APIGen
APIGen --> Glue[Generate SV/Python API Glue Code]
TBMod --> Fileset[Produce Ordered Compilation Fileset]
Glue --> Fileset
Fileset --> Done[Ready for Compilation]
style Check fill:#ffffcc
style SVGen fill:#ccffcc
style APIGen fill:#ccccff
style Done fill:#ccffcc
Runtime (Simulation)
^^^^^^^^^^^^^^^^^^^^
.. mermaid::
sequenceDiagram
participant Sim as HDL Simulator
participant TB as Testbench Module
participant PyHDL as PyHDL-IF
participant Runtime as HDLSimRuntime
participant Pytest as pytest
Sim->>TB: Load & Initialize
TB->>PyHDL: Register Transactor APIs
TB->>Runtime: configure_objfactory("MyTB")
Runtime->>Runtime: Patch MyTB.__init__
TB->>Pytest: pyhdl_pytest()
Pytest->>Runtime: Create MyTB instance
Runtime->>PyHDL: Lookup registered components
PyHDL-->>Runtime: Return SV proxies
Runtime-->>Pytest: Return TestbenchProxy
Pytest->>Runtime: Call test methods
Runtime->>PyHDL: Forward to SV APIs
PyHDL->>TB: Execute in simulator
TB-->>PyHDL: Return results
PyHDL-->>Runtime: Return to Python
Runtime-->>Pytest: Complete test
Pytest->>Sim: $finish
Code Generation Details
-----------------------
Testbench Module Structure
^^^^^^^^^^^^^^^^^^^^^^^^^^^
The generated top-level testbench module has this structure:
.. code-block:: systemverilog
module MyTB_tb;
import pyhdl_if::*;
import RVXtor::*;
// Instance HDL components
MyTB_hdl u_hdl();
initial begin
// Register transactors with PyHDL-IF
// ... registration code ...
// Configure Python ObjFactory
pyhdl_configure_objfactory("mypackage.MyTB");
// Launch pytest
pyhdl_pytest();
$finish;
end
endmodule
HDL Module Structure
^^^^^^^^^^^^^^^^^^^^
The ``_hdl`` module contains the hardware components:
.. code-block:: systemverilog
module MyTB_hdl;
// Extern component instances
dut u_dut(...);
// Generated transactor instances
RVXtor u_xtor(...);
// Signal bindings from __bind__
assign u_dut.rv_if = u_xtor.xtor_if;
endmodule
Python Runtime Factory
^^^^^^^^^^^^^^^^^^^^^^
At runtime, the ``PyTestbenchFactory`` creates proxy objects:
.. code-block:: python
class TestbenchProxy:
def __init__(self):
# Look up registered SV components via PyHDL-IF
self.xtor = HdlObjRgy.inst().find("top.xtor")
self.dut = None # Extern, no Python API
Key Classes
-----------
* ``SVTestbenchGenerator``: Generates SystemVerilog testbench modules
* ``PyTestbenchFactory``: Creates runtime proxy objects for Python tests
* ``HDLTestbenchChecker``: Validates profile rules
* ``TransactorJsonApiGenerator``: Generates PyHDL-IF API definitions
* ``GenTB``: `DFM `_ task for testbench generation
See :doc:`api_reference` for detailed API documentation.