If you've ever struggled with DPI-C wrappers just to reuse your Python libraries in a SystemVerilog testbench, there's a much easier way — and it's called PyStim.
As someone working in RTL design, I've often used Python to rapidly prototype RTL modules because it's fast, flexible, and developer-friendly. But integrating those Python models into a SystemVerilog verification environment traditionally required writing cumbersome C wrappers and DPI-C glue code.
Why You’ll Love PyStim
-
Zero C/C++ Glue
- No hand-rolled wrappers or autogenerated stubs—just point PyStim at your Python module and go.
-
True Object Accessibility
- Instantiate Python classes, invoke methods, and pass data back and forth as native SystemVerilog objects.
-
Inline Python Execution
- Run arbitrary Python scripts or snippets directly from your RTL simulator.
What You Need
- Python ≥ 3.7
- A SystemVerilog Simulator: QuestaSim, VCS, Xcelium, or Verilator ≥ 5.034
- Linux Host: RHEL 7/8/9 or Ubuntu ≥ 22.04
Example
Python model (counter.py):
#counter.py
class Counter:
def __init__(self, initial=0):
self.value = initial
def inc(self):
self.value += 1
return self.value
SystemVerilog integration:
import pystim_pkg::*;
module simple_calc();
typedef pystim_pkg::pystim py;
initial begin
// Python interpreter initialization
py::initialize_interpreter();
begin
py_object result;
begin
// import Counter from counter
automatic py_object Counter = py_module::import_("counter").attr("Counter");
// Directly instantiate Python Counter object
automatic py_object cnt = Counter.call(py::int_(0));
// Call Python method without DPIC wrappers
repeat(3)begin
result = cnt.attr("inc").call();
$display("Cnt: %0d", result.cast_int().get_value());
end
end
end
// Finalize PyStim
py::finalize_interpreter();
end
endmodule
Running this testbench will directly interact with the Python object, yielding output:
# Cnt: 1
# Cnt: 2
# Cnt: 3
Executing Arbitrary Python Code
PyStim can directly run any Python script or code snippet.
...
automatic py_dict globals = py::globals();
automatic py_dict locals = py_dict::create_empty();
locals.set(py::string_("name"),py::string_("Python"));
py::exec("print('Hello from {}!'.format(name))", globals, locals);
...
The inherent simplicity makes it much easier to reuse Python libraries and achieve rapid prototyping.
Final Thoughts:
The reduced integration complexity offered by PyStim has substantially improved my workflow. By enabling direct Python interaction within SystemVerilog, it accelerates both testing and development, making it a powerful and efficient tool for tackling complex RTL design & verification tasks.