python-dpic · tutorial
DPI-C from scratch, then Python as a golden model
An incremental tutorial on the SystemVerilog Direct Programming Interface, measured on Verilator 5.052, ending with Python functions called as bit-exact reference models from a SystemVerilog testbench.
Get started
Each step is a guide plus a lab. The guide reads in the browser (this site, or tutorial/index.html from a clone, offline). The lab is a folder of small SystemVerilog + C/Python testbenches that Verilator builds and runs; check.py asserts every number the guide quotes.
| You need | For | Measured with |
|---|---|---|
| Verilator 5.x | every lab (--binary --timing) | 5.052 |
| A C/C++ compiler | every lab | Apple clang, macOS x86_64 |
Python 3 with python3-config | check.py; embedding in steps 07–08 | 3.14 |
| numpy | step 08 (FIR golden model) | 2.x |
| z3 | step 06 (randomize() calls it as an external solver) | |
| ccache (optional) | faster rebuilds |
git clone https://github.com/leandrotozzi/python-dpic.git
cd python-dpic/tutorial/01_first_call/lab
python3 check.py # builds every testbench in build/, runs them, asserts the results
Every guide has the same layout: text → worked examples → exercises with hidden solutions → self-graded quiz → lab walkthrough → cheat sheet. Try an exercise before opening its solution; the files it refers to are in the step's lab/ (lab/ex/ for exercises). The index on the left of each guide ticks off sections as you read; the cards below show that progress.
Everything was measured on macOS. Linux runs the same commands; the few macOS-only details are flagged on the Verilator gaps page. Commercial simulators (Questa, VCS, Xcelium) follow the same IEEE 1800 Annex H rules; where they differ from Verilator the guides say so.
Part A · DPI-C
Spear & Tumbush ch. 12First call
import "DPI-C", pure, renaming, libm, how Verilator compiles and links C, the generated prototype header, extern "C".
Data types
The SV↔C type map, svBitVecVal/svLogicVecVal, wide vectors, directions, 2-state vs 4-state.
State and handles
Static vs per-instance state, chandle, C++ models behind a C ABI, lifetime and leaks, threads.
Arrays, structs, strings
Fixed and open arrays, svOpenArrayHandle, packed arrays, struct layout, string ownership.
Export and context
Calling SV from C, context vs pure, scopes, why exported tasks can't wait in Verilator.
Golden model in C
DUT + C reference + scoreboard, random stimulus, mutants, cost per call, stream vs batch.
Part B · Python
the same SV imports, backed by PythonEmbedding Python
The CPython C API from a DPI library: lifecycle, imports, refcounts, errors, the GIL, venvs.
Python golden model
zlib and numpy as reference models, wide ints, batching, measured C vs Python, pysv / PyHDL-IF / cocotb.
What doesn't work in Verilator
52 measured gaps in one place, silent wrong results first, each with its workaround and the lab that proves it.
Steps 06 and 08 share two DUTs: crc32_stream.sv (CRC-32/IEEE, bit-exact with zlib.crc32) and fir8.sv (8-tap Q1.15 FIR, round half-up, saturating). Raw measurements behind every guide: NOTES.md.
References
- IEEE Std 1800-2023, clause 35 (DPI), Annex H (DPI C layer), Annex I (
svdpi.h). The normative source. - Spear & Tumbush, SystemVerilog for Verification, 3rd ed., Springer 2012, ch. 12 “Interfacing with C/C++”. Steps 01–06 follow it; its errata are on the gaps page.
- Verilator manual, “Direct Programming Interface (DPI)” and “Connecting to C++”.
- Doulos, SystemVerilog DPI tutorial.
- AMD UG900, “Open Arrays in DPI” / “Support for svdpi.h functions” (a clear vendor summary of Annex H/I).
- AMIQ, How to Call C-functions from SystemVerilog Using DPI-C and How to Connect SystemVerilog with Python (2019).
- Python docs, Embedding Python in Another Application and Python Initialization Configuration (PEP 587 / PEP 741).
- M. Ballance, Properly Introducing Python to your UVM Testbench, DVCon US 2026 (PyHDL-IF).
- Libraries for later: pysv, PyHDL-IF, cocotb, pyuvm.