【原创】SystemVerilog中传说的DPI

自SystemVerilog3.1a之后,SystemVerilog推出了一个与第三方语言进行交互的强大功能,称之为DPI,DPI的全称就是Direct Programming Interface,是SystemVerilog与其他编程语言的一种接口,目前经常被用到的是SystemVerilog与C(C++)之间的交互,本文示例也将以C语言和SystemVerilog示例。

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。

通过DPI可以在SystemVerilog中调用C语言中的function(C语言中没有task),当然,也可以通过DPI调用SystemVerilog中的task和function。如下例: 

【原创】SystemVerilog中传说的DPI_第1张图片

DPI实现了SystemVerilog与其他语言的接口,所以其一般由两部分组成,即SystemVerilog层和其他语言层,并且这两层彼此之间是相互独立的,两者的编译也是相互独立的,进行这样两层结构的出发点是设计人员对于其他语言开发的模块在SystemVerilog中使用的迫切需求(特别是C和C++)。在DPI的这种分层结构中,遵循的是一种“黑盒”规则:组件的规范和实现明确分开,实际实现对该语言编写代码的其余部分是透明的,而对于通过DPI使用其方法的语言为不透明的。例如,C语言编写的方法,对于通过DPI使用其的SystemVerilog来说是一个黑盒子但是SystemVerilog无需更改即可对其进行调用。那么在具体的使用过程中应该如何快速的使用DPI-C呢,我们下面分别从SV调用C函数和C调用SV方法进行示例说明。

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);

从上述语法结构我们可以看出,import使用方式主要有三种,下面我们将示例import的三种用法。这里需要注意,pure和context仅能在import时使用,并且pure不能用于task。

1.1 context方式

导入方法时,有时需要知道被调用的环境的上下文信息,以决定调用PLI TF、ACC还是VPI方法或者其中又调用SystemVerilogexport的方法,简单说就是import的方法访问SystemVerilog中除了形参传入的数据以外的数据或者方法时,就必须要使用context。使用context导入方法的方式,因为需要记录import方法调用时上写文环境,会带来一些额外的开销导致仿真的效率变低,所以一般情况下不要使用context方式。使用import方式调用C函数的示意图如下图所示。

【原创】SystemVerilog中传说的DPI_第2张图片

【示例】

【原创】SystemVerilog中传说的DPI_第3张图片

【仿真结果】

图片

1.2 pure方式

与context相比较,使用pure的函数能够提高仿真效率。使用pure的函数的结果仅依赖于其输入参数。一个pure函数将严格依据其输入计算输出,跟外部环境没有任何交互,也就是说pure函数不会访问任何全局或者静态变量,不会进行文件操作,不会跟函数体外的事物交互。如果没有使用pure函数的输出,SystemVerilog编译器会优化掉对该函数的调用,对于输入参数相同的两次调用,编译器会将第二次调用直借用第一次的输出进行替换。一般non_void类型的函数指定为pure,并且该函数没有output和inout类型。

【示例】 

【原创】SystemVerilog中传说的DPI_第4张图片

【仿真结果】 

【原创】SystemVerilog中传说的DPI_第5张图片【原创】SystemVerilog中传说的DPI_第6张图片

 虽然pure可以提高仿真性能,但是并不是所有的地方都可以使用pure,就像上文所述之一,如果对文件进行操作,即此时存在函数体与函数体外进行交互时,不能在函数导入时指定pure。

【示例】 

【原创】SystemVerilog中传说的DPI_第7张图片

 【仿真结果】

【原创】SystemVerilog中传说的DPI_第8张图片

 当遇到如下情况时,不要使用在import的函数前使用pure:

l 文件操作

l 对任何事物的读写,包括I/O, 环境变量,来自操作系统,程序,进程的对象, shared memory, socket等

l 访问任何永久变量,比如全局的或静态的变量,此时导入的方法就不再是pure方法了;

以上是如何从C语言程序中如何import函数或者方法到SystemVerilog中,那么SystemVerilog中的函数和任务也可以export到C语言中,被C语言程序使用。

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基本雷同。

【原创】SystemVerilog中传说的DPI_第9张图片

1.4 import步骤

通过上述示例,总结如何import C程序中的函数的步骤如下:

Step1 :在SystemVerilog中声明要导入的函数

         import“DPI-C” function to_sv_func;

Step2 :在SystemVerilog中调用从C程序中导入的函数

Step3 :在C程序中定义要导出到SystemVerilog中的函数

这里需要注意,导入的函数跟正常的SystemVerilog函数是一样的,函数调用时会被阻塞立即执行,不会消耗仿真时间,这也是跟task的一大区别,这里也需要注意,如果企图在C程序中调用一个SystemVerilog的任务,那么这个从C程序导入到SystemVerilog中的方法只能是任务,不能是task,下文将说明其中缘由。

2 SV中export方法

语法:

export "DPI" [to_c_name =] function from_sv_name;export "DPI" [to_c_name =] task from_sv_name;

从上述语法结构我们可以看出,不管函数还是任务在导出是,都不需要指明返回类型和参数列表。export流程如下图所示:

【原创】SystemVerilog中传说的DPI_第10张图片

2.1 调用SystemVerilog中的函数

【示例】 

【原创】SystemVerilog中传说的DPI_第11张图片

【仿真结果】

【原创】SystemVerilog中传说的DPI_第12张图片

示例中实现了在C程序中调用SystemVerilog已经定义好的function,除此之外,C程序中也可以调用SystemVerilog中已经定义好的task,如下例。

2.2 调用SystemVerilog中的任务

【示例】 

【原创】SystemVerilog中传说的DPI_第13张图片

【仿真结果】 

【原创】SystemVerilog中传说的DPI_第14张图片

示例中,因为C程序中的disp调用了导入的export_sv_func是一个task,而在SystemVerilog中我们知道任务可以调用函数和任务,但是函数不能调用任务,所以C程序中的disp在import到SystemVerilog中时,必须指定为task,并且需要指明为context(因为这task的执行还与其他task的执行有关)。

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等。

在上述的C程序的示例中,我们在头文件中都使用了一个特殊的头文件svdpi.h,那么这个svdpi.h是干什么的呢?下面简要说明下。

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能起到抛砖引玉的作用,互相学习。

更多内容请关注下面公众号!

【原创】SystemVerilog中传说的DPI_第15张图片

本文纯属学习之用,欢迎指正文中不足,封面图片若有侵权,请及时沟通!

 

你可能感兴趣的:(SystemVerilog,dpi-c,开发语言)