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).
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<br/>(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
ExternprotocolReference existing HDL modules
Provide SystemVerilog source filesets via
@annotation_filesetConnect to other SV components via signals/interfaces
Example:
@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_ifinterface
Example:
@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:
No Signal-Level Crossing: Python components cannot connect directly to signals in the SV domain
TLM Boundary: Communication between domains uses transaction-level modeling (method calls on xtor_if)
Extern Isolation: Extern components can only connect to other SV components (Extern or XtorComponent)
Generation Flow¶
Build Time (GenTB Task)¶
flowchart TD
Start[Zuspec Component Class] --> Check[Profile Checking]
Check --> |Valid| SVGen[SV Generation]
Check --> |Errors| Fail[Report Errors]
SVGen --> Trans[Generate Transactor Modules<br/>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)¶
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:
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:
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:
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 modulesPyTestbenchFactory: Creates runtime proxy objects for Python testsHDLTestbenchChecker: Validates profile rulesTransactorJsonApiGenerator: Generates PyHDL-IF API definitionsGenTB: DFM task for testbench generation
See API Reference for detailed API documentation.