遇到了这样一个需求,许多验证人员用python用的很熟练,但是只能通过vpi调用c代码,要用c代码实现相同功能的python代码过于繁琐,所以想着能不能在c中调用python中的方法,将其包一层变为c函数,然后用vpi调用这个c函数来实现:
代码中展示了调用有参python方法和无参python方法两种用法
#includemakefile文件:#include PyObject* callPythonFun(char* pyName,char* funcName,PyObject* pArg){ PyObject* pModule = NULL; // PyObject* pDict = NULL; PyObject* pFunc = NULL; PyObject* result = NULL; // PyRun_SimpleString("import os"); PyRun_SimpleString("import sys"); // PyRun_SimpleString("print(os.listdir("./"))"); // PyRun_SimpleString("sys.path.append("/netapp/home/wenqi/tools/runpyinc")"); PyRun_SimpleString("sys.path.append("./")");// change path to current file pModule = PyImport_ImportModule(pyName); //引入py file if (!pModule) { printf("[ERROR]can't import python filen"); return ; } pFunc = PyObject_GetAttrString(pModule, funcName); //从字典属性中获取函数 // printf("[NOTE]loading......n"); // pFunc = PyObject_GetAttrString(pModule, "add"); if (!pFunc || !PyCallable_Check(pFunc)) { printf("[ERROR]can't find function in python filen"); return ; } result = PyEval_CallObject(pFunc, pArg); //调用函数,并得到python类型的返回值 return result; } int main() { // 直接调用python脚本的方法 // FILE * fp; // char buffer[80]; // fp=popen("python test.py","r"); // fgets(buffer,sizeof(buffer),fp); // printf("%s",buffer); // pclose(fp); //init python environment Py_Initialize(); if (Py_IsInitialized()) { // printf("initn"); }else{ printf("[ERROR]py init failn"); return ; } // example 1 PyObject* pArg = Py_BuildValue("(i, i)", 1, 2); //参数类型转换,传递两个整型参数 PyObject* result = callPythonFun("mypy","add",pArg);// 使用接口调用python脚本中函数add(a,b) int sum = 0; PyArg_Parse(result, "i", &sum); //将python类型的返回值转换为c/c++类型, "i" ->>> int printf("result = %dn", sum); // example 2 callPythonFun("mypy","printcharint",NULL);//无参数的情况 //close python environment Py_Finalize(); return 0; }
all: run run: main.o @gcc -L/usr/lib64/python3.4/ -lpython3 main.o -o run main.o: main.c @gcc -c -w main.c -I/usr/include/python3.4/ clean: @rm -rf *.pyc run
这里重点是链接上Python To C的库,具体的头文件和库文件位置需要对应自己的环境
mypy.py:#!/tools/bin/python3
import os
import re
import sys
def add(a,b):
print("in python function add")
return a + b
def testout():
print ("in python function testout")
def printcharint():
charf = "charinfo"
intf = 1
print(charf + " " + str(intf))
if __name__=="__main__":
print("in python")
make后运行run结果如下:
[lee@ubuntu runpyinc]$ ./run in python function add result = 3 charinfo 1解决基于VCS使用vpi调用包含了python的c 首先c文件要引入vpi_user.h mod_info.c:
#include#include "vpi_user.h" #include void module_info() { vpiHandle moditH, topmodH; moditH = vpi_iterate(vpiModule, NULL); if(!moditH) { vpi_printf(" Error: no modules in the designn"); } while (topmodH = vpi_scan(moditH)) { vpi_printf("Top module Full Name: %sn",vpi_get_str(vpiFullName, topmodH)); vpi_printf(" Top module Name: %sn", vpi_get_str(vpiName, topmodH)); } } void register_my_systfs() { s_vpi_systf_data task_data_s; p_vpi_systf_data task_data_p = &task_data_s; task_data_p->type = vpiSysTask; task_data_p->tfname = "$module_info"; task_data_p->calltf = (int(*)()) module_info; task_data_p->compiletf = 0; vpi_register_systf(task_data_p); } PyObject* callPythonFun(char* pyName,char* funcName,PyObject* pArg){ //………………………………略 } void hello_world(){ vpi_printf("*********this is print by vpi************n"); Py_Initialize(); if (Py_IsInitialized()) { // printf("initn"); }else{ printf("[ERROR]py init failn"); return ; } // example 1 PyObject* pArg = Py_BuildValue("(i, i)", 1, 2); //参数类型转换,传递两个整型参数 PyObject* result = callPythonFun("mypy","add",pArg);// 使用接口调用python脚本中函数add(a,b) int sum = 0; PyArg_Parse(result, "i", &sum); //将python类型的返回值转换为c/c++类型, "i" ->>> int printf("result = %dn", sum); // example 2 callPythonFun("mypy","printcharint",NULL);//无参数的情况 //close python environment Py_Finalize(); }
hello_world()即为包了一层的c调用python的方法,就是上面的main函数,因为只是被vpi调用,c中不需要有主函数的概念了
然后编译生成mod_info.o makefile如下:mod_info.o: mod_info.c @gcc -c -w -fPIC mod_info.c -I/usr/include/python3.4/ -I/tools/install/synopsys/vcs_mx/vO-2018.09-SP2/include clean: @rm -rf *.o
这里与上面的不同是要添加上vpi_user.h头文件所在的目录,并且只需要生成.o,具体的路径还是要对应自己的环境,我这里是在VCS的目录下找到的
然后构建VCS仿真环境已一个简单的案例为例:
pipe.v:module pipe ( out, in, clk );
output out; reg out;
input in, clk;
always @ (in)
@ (posedge clk)
out <= repeat (2) @ (posedge clk) in;
endmodule
test.v:
module hello;
wire a, b, c;
initial
begin
$hello_world; //调用c中的调用python的方法
$module_info;
end
pipe p1 (a, b, c);
//stimuli
//monitor response
endmodule
vpi.tab:
$module_info call=module_info $hello_world call=hello_world启动脚本runvcs.sh:
vcs -R -full64 -fsdb -sverilog +vpi -v pipe.v test.v -lpython3 -P vpi.tab mod_info.o最终的VCS仿真报告
../simv up to date
Chronologic VCS simulator copyright 1991-2018
Contains Synopsys proprietary information.
Compiler version O-2018.09-SP2-11_Full64; Runtime version O-2018.09-SP2-11_Full64; May 17 16:15 2022
*********this is print by vpi************
in python function add
result = 3
charinfo 1
Top module Full Name: hello
Top module Name: hello
V C S S i m u l a t i o n R e p o r t
Time: 0
CPU Time: 0.290 seconds; Data structure size: 0.0Mb
可以看到python中有参数和无参数的方法都已被正确调用,实际使用时还会向c中传参,还要交互等等,就看具体需求具体修改了,本文只是拼凑出了一种基于VCS使用VPI调用c再调用python的方法,具体效果不再详述。



