遇到了这样一个需求,许多验证人员用python用的很熟练,但是只能通过vpi调用c代码,要用c代码实现相同功能的python代码过于繁琐,所以想着能不能在c中调用python中的方法,将其包一层变为c函数,然后用vpi调用这个c函数来实现:

VPI—>C—>Python

首先解决c调用python

main.c代码如下(引入头文件 Python.h ):

代码中展示了调用有参python方法和无参python方法两种用法

#include <stdio.h>
#include <Python.h>

/* 
	function callPythonFun();
	pyName ----> python文件名
	funcName---> python文件中要调用的函数名
	pArg ------> 通过Py_BuildValue()格式化好的参数
*/
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 file\n");
    	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 file\n");
		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("init\n");
	}else{
		printf("[ERROR]py init fail\n");
		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 = %d\n", sum);

	// example 2
	callPythonFun("mypy","printcharint",NULL);//无参数的情况

	//close python environment
	Py_Finalize();
	return 0;
}
makefile文件:
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 <stdio.h>
#include "vpi_user.h"
#include <Python.h>
void module_info()
{
  vpiHandle moditH, topmodH;
  moditH = vpi_iterate(vpiModule, NULL);
  if(!moditH) {
     vpi_printf("    Error: no modules in the design\n");
  }
   while (topmodH = vpi_scan(moditH)) {
    vpi_printf("Top module Full Name: %s\n",vpi_get_str(vpiFullName, topmodH));
    vpi_printf(" Top module Name: %s\n", 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("init\n");
	}else{
		printf("[ERROR]py init fail\n");
		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 = %d\n", 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的方法,具体效果不再详述。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐