はじめに
SystemVerilog側からPython側の処理を呼び出してみるテストだよ。
import "DPI-C" function void py_initialize();
import "DPI-C" function void py_finalize();
import "DPI-C" function void py_append(string path);
import "DPI-C" function void hello();
module test;
initial begin
py_initialize();
py_append(".");
hello();
py_finalize();
$finish;
end
endmodule
下記が今回呼び出したい(この世界に何も生み出さない非生産的な)Python側の処理で、
def hello():
print("Hello")
そのPython側の処理を呼び出すための、C言語の関数が、
#include "my_python.h"
void hello(void) {
py_call_function_void("hello", "hello", "");
}
です。SystemVerilog側からPythonを呼び出す、と言いながら、実際にやっていることは、SystemVerilogからCを呼び出す、そのCがPythonを呼び出す、という二段構成だったりします。要するに、後段の処理はもはやSystemVerilogとか一ミリも関係ない、ただのPython/C APIの話ってこと。
……というわけで、ここから先はPython/C APIについて適当にググりながら書く感じになるどす。SystemVerilog?なにそれおいしいの?ってかんじ。
#ifndef MY_PYTHON_H
#define MY_PYTHON_H
#include <stdarg.h>
#define PY_SSIZE_T_CLEAN
#include <Python.h>
void py_initialize(void);
void py_finalize(void);
void py_append(const char* path);
void py_call_function_void(
const char* module_name,
const char* function_name,
const char* types,
...
);
#endif
#include "my_python.h"
#include <stdio.h>
void py_initialize(void) {
Py_Initialize();
}
void py_finalize(void) {
Py_Finalize();
}
void py_append(const char* path) {
PyObject* sys_path = PySys_GetObject("path");
PyObject* dir = PyUnicode_FromString(path);
PyList_Append(sys_path, dir);
Py_DECREF(dir);
}
void py_call_function_void(
const char* module_name,
const char* function_name,
const char* types,
...
){
PyObject* module;
PyObject* func;
PyObject* args;
PyObject* result;
va_list ap;
module = PyImport_ImportModule(module_name);
func = PyObject_GetAttrString(module, function_name);
va_start(ap, types);
if (types && types[0] != '\0')
args = Py_VaBuildValue(types, ap);
else
args = PyTuple_New(0);
va_end(ap);
result = PyObject_CallObject(func, args);
Py_DECREF(result);
Py_DECREF(args);
Py_DECREF(func);
Py_DECREF(module);
}
コンパイルしてリンクして実行すると、Python側のHelloが表示されます。
[foo@i7-12700 ~]$ gcc -fPIC -c my_python.c -I/usr/include/python3.6m
[foo@i7-12700 ~]$ gcc -fPIC -c hello.c -I/usr/include/python3.6m
[foo@i7-12700 ~]$ gcc -shared -o my_dpi.so my_python.o hello.o -L/usr/lib64 -lpython3.6m
[foo@i7-12700 ~]$ dsim -sv_lib my_dpi.so test.sv -top test
Copyright (C) 2017-2025 Altair Engineering Inc. All rights reserved.
=N:[UsageMeter (2025-12-01 23:30:16 +0900)] usage server initial connection
=N:[License]
Licensed for Altair DSim Cloud.
=N:[License] New lease granted.
Analyzing...
Elaborating...
Top-level modules:
$unit
test
Found 4 unique specialization(s) of 4 design element(s).
Optimizing...
Building models...
PLI/VPI access: (none)
Simulation time precision is 1ns.
Linking image.so...
Using default typical min/typ/max.
=S:Begin run-time elaboration and static initialization...
=N:Starting event scheduler...
Hello
=T:Simulation terminated by $finish at time 0 (test.sv:12);
Run directory: /home/foo
System timescale is 1ns / 1ns
Altair DSim version: 2025.1.0 (b:R #c:449 h:df8da7d488 os:rocky_8.10)
Random seed: (defaulted to 1)
ここらからさらにもうちょっと頑張ると、Python側のクラスのインスタンスを生成して、そいつを使ってなんやかんやできるようになったりならなかったりします(雑
おわりに
こういうのもあるらしいですわよ。札束で他人の頬をペチペチできる富裕層のみなさま。