Quick Start¶
This guide walks you through creating your first HDL testbench with Zuspec HDLSim backend.
Prerequisites¶
Python 3.9+
Zuspec dataclasses
HDL simulator (Verilator, VCS, etc.)
DV Flow Manager (recommended for automated workflows)
Installation¶
pip install zuspec-be-hdlsim zuspec-dataclasses pyhdl-if
Step 1: Define Your Components¶
Create a file my_testbench.py:
import zuspec.dataclasses as zdc
from zuspec.dataclasses.protocols import Extern, XtorComponent
from zuspec.dataclasses import Signal, annotation_fileset
# Define the DUT wrapper
@zdc.dataclass
class DutWrapper(zdc.Component, Extern):
"""Wrapper for existing counter.sv module."""
clock: Signal = zdc.input()
reset: Signal = zdc.input()
count_out: Signal = zdc.output()
@annotation_fileset(sources=["rtl/counter.sv"])
def __post_init__(self):
pass
# Define clock/reset transactor protocol
class ClkRstIf:
async def reset_pulse(self, cycles: int):
"""Assert reset for N cycles."""
...
async def wait_cycles(self, cycles: int):
"""Wait for N clock cycles."""
...
# Define clock/reset transactor
@zdc.dataclass
class ClkRstXtor(XtorComponent[ClkRstIf]):
"""Clock and reset generator."""
clock: Signal = zdc.output()
reset: Signal = zdc.output()
# Implementation details handled by generator
# Define top-level testbench
@zdc.dataclass
class CounterTB(zdc.Component):
"""Counter testbench."""
dut: DutWrapper = zdc.inst()
clkrst: ClkRstXtor = zdc.inst()
def __bind__(self):
"""Define signal bindings."""
return (
(self.clkrst.clock, self.dut.clock),
(self.clkrst.reset, self.dut.reset),
)
Step 2: Create Your Test¶
Create test_counter.py:
import pytest
from zuspec.be.hdlsim import HDLSimRuntime
from my_testbench import CounterTB
@pytest.fixture
def tb():
"""Testbench fixture."""
# Runtime will be configured by SV before pytest runs
return CounterTB()
async def test_reset(tb):
"""Test counter reset behavior."""
# Reset the DUT
await tb.clkrst.reset_pulse(10)
# Wait and observe
await tb.clkrst.wait_cycles(100)
# Assertions would go here
assert True
Step 3: Create Workflow Specification¶
The recommended approach is to use DV Flow Manager (DFM) to automate
your build and run workflows. Create flow.yaml:
package:
name: counter_tb
tasks:
- name: GenTB
uses: zuspec.be.hdlsim.dfm.GenTB
with:
class_name: my_testbench.CounterTB
- name: SimImage
uses: hdlsim.vlt.SimImage
needs: [GenTB]
with:
top_module: CounterTB_tb
- name: SimRun
uses: hdlsim.vlt.SimRun
needs: [SimImage]
with:
plusargs:
- pyhdl.pytest=test_counter.py::test_reset
Step 4: Create RTL¶
Create rtl/counter.sv:
module counter (
input logic clock,
input logic reset,
output logic [7:0] count_out
);
logic [7:0] count;
always_ff @(posedge clock) begin
if (reset)
count <= 8'h0;
else
count <= count + 1;
end
assign count_out = count;
endmodule
Step 5: Generate and Run¶
Using DFM, generate the testbench:
dfm run GenTB
This produces:
generated/CounterTB_hdl.sv- HDL module with component instancesgenerated/CounterTB_tb.sv- Testbench wrapper modulegenerated/ClkRstXtor.sv- Generated transactorgenerated/ClkRstXtor_api.json- PyHDL-IF API definitiongenerated/test_countertb.py- Generated test wrapper
Build and run the simulation:
dfm run SimImage # Compile with Verilator
dfm run SimRun # Run simulation
What Happens at Runtime¶
Next Steps¶
Components - Learn about component types in detail
DV Flow Manager Integration - More DFM workflow patterns
Examples - More complex examples
API Reference - API documentation
Troubleshooting¶
Import errors: Ensure all dependencies are installed:
pip install -U zuspec-be-hdlsim zuspec-dataclasses pyhdl-if
Generation fails: Check that your component follows profile rules:
from zuspec.be.hdlsim.checker import HDLTestbenchChecker
checker = HDLTestbenchChecker()
checker.check_component(CounterTB)
print(checker.get_errors())
Runtime errors: Verify PyHDL-IF registration in generated SV testbench module.