SystemVerilog中传说的DPI
0 大鱼吃小鱼的DPI
在上世纪的时候,开发SuperLog的Co-Design Automation公司实现了SuperLog与C语言的交互,称之为CBlend技术。同时,很多其他EDA公司也开始开发类似的技术。2001年的时候Co-Design Automation公司向Accellera发布了SuperLog扩展综合子集ESS。2002年Synopsys收购了Co-Design Automation,Synopsys结合Co-Design开发的SuperLog与C语言交互的CBlend技术也开发了适合自己仿真器的交互的 DirectC接口(VCS DirectC),然后将DirectC和CBlend捐献给了Accellera,Accellera的SystemVerilog标准委员会把这两个捐献技术合并在一起,并定义了DPI接口,使得DPI能够与任何仿真器一起工作。又经过若干年的发展,DPI又进阶为了DPI-C(IEEE 1800-2012之后),渐渐地DPI逐步的被DPI-C替换成为了主流。后续我们说的DPI如果没有特殊说明均指DPI-C。
1 SV中import方法
语法:
import "DPI" [from_c_name =] [pure][context] function type to_sv_name(args); import "DPI" [from_c_name =] [context] task to_sv_ame (args);
1.1 context方式
导入方法时,有时需要知道被调用的环境的上下文信息,以决定调用PLI TF、ACC还是VPI方法或者其中又调用SystemVerilogexport的方法,简单说就是import的方法访问SystemVerilog中除了形参传入的数据以外的数据或者方法时,就必须要使用context。使用context导入方法的方式,因为需要记录import方法调用时上写文环境,会带来一些额外的开销导致仿真的效率变低,所以一般情况下不要使用context方式。使用import方式调用C函数的示意图如下图所示。
与context相比较,使用pure的函数能够提高仿真效率。使用pure的函数的结果仅依赖于其输入参数。一个pure函数将严格依据其输入计算输出,跟外部环境没有任何交互,也就是说pure函数不会访问任何全局或者静态变量,不会进行文件操作,不会跟函数体外的事物交互。如果没有使用pure函数的输出,SystemVerilog编译器会优化掉对该函数的调用,对于输入参数相同的两次调用,编译器会将第二次调用直借用第一次的输出进行替换。一般non_void类型的函数指定为pure,并且该函数没有output和inout类型。
【示例】
虽然pure可以提高仿真性能,但是并不是所有的地方都可以使用pure,就像上文所述之一,如果对文件进行操作,即此时存在函数体与函数体外进行交互时,不能在函数导入是指定pure。
【示例】
当遇到如下情况时,不要使用在import的函数前使用pure:
l 文件操作
l 对任何事物的读写,包括I/O, 环境变量,来自操作系统,程序,进程的对象, shared memory, socket等
l 访问任何永久变量,比如全局的或静态的变量,此时导入的方法就不再是pure方法了;
1.3 generic方式
那些既没有明确声明为pure,也没有声明为context的缺省状态下的函数称为generic函数(Sutherland中的一篇文章称之为generie C函数,这种方式并没有在IEEE1800之中规定,只是将既不是pure也不是context那类方法称之为generic函数)。generic C函数可以作为Verilog函数或者Verilog任务导入。任务或者函数可以由输入、输出以及inout的参数。generic函数调用一个导出任务或者访问SystemVerilog数据对象的PLI函数,会导致仿真器崩溃。因此,正确的声明导入的函数为pure、context还是generic是用户的责任。generic函数导入的流程如下图所示,其实与context和pure基本雷同。
1.4 import步骤
通过上述示例,总结如何import C程序中的函数的步骤如下:
Step1 :在SystemVerilog中声明要导入的函数
import“DPI-C” function to_sv_func;
Step2 :在SystemVerilog中调用从C程序中导入的函数
Step3 :在C程序中定义要导出到SystemVerilog中的函数
2 SV中export方法
语法:
export "DPI" [to_c_name =] function from_sv_name; export "DPI" [to_c_name =] task from_sv_name;从上述语法结构我们可以看出,不管函数还是任务在导出是,都不需要指明返回类型和参数列表。export流程如下图所示:
2.1 调用SystemVerilog中的函数
【示例】
【仿真结果】
2.2 调用SystemVerilog中的任务
【示例】
2.3 export步骤
通过上述示例,总结如何export SystemVerilog中方法(这里以function为例)的步骤如下:
Step1 :在SystemVerilog中声明要导出的函数
export “DPI-C” function export_sv_func;
Step2 :在SystemVerilog中定义要导出的函数
function void export_sv_func();
...// 函数体
endfunction
Step3 : 在C程序中通过extern声明要导入一个外部函数
extern void export_sv_func(void);
Step4 :在C程序中调用SystemVerilog中被导入到C程序中的函数
这里可能会有人有疑问,import或者export一般声明在什么地方呢?在SystemVerilog中,只要是正常SV方法可以被声明的地方就都可以通过DPI直接import和export方法,比如module、program、interface、construct、package等。
3 svdpi.h和svdpi_src.h
在C程序与SystemVerilog相互之间导入导出方法时,除了使用svdpi.h之外,其实有时还需要使用另一个头文件svdpi_src.h,这两个头文件的作用如下:
svdpi.h:C本身并不具有与SV进行类型交互的,所以必须要使用svdpi.h,其中定义了所有的基本数据类型、接口函数记忆一些宏定义和参数。该文件不依赖于任何一种仿真器,所有的仿真器都支持。
svdpi_src.h仅仅只定义一种数据结构实现了SystemVerilog的2值和4值压缩数组
本文通过一些简短的示例说明了如何通过DPI实现C程序和SystemVerilog之间的交互,希望对于准备学习DPI能起到抛砖引玉的作用,互相学习。