Verilog与C之间进行程序交互,PLI(Programming Language Interface)经过了TF,ACC,VPI等模式。

使用PLI可以生成延时计算器,来连接和同步多个仿真器,并可以通过波形显示等调试工具。

通过PLI方式连接一个简单的C程序,需要编写很多代码,并理解多仿真阶段的同步,调用段,实例指针等概念。

PLI方式给仿真带来了额外的负担,为了保护Verilog的数据结构,仿真器需要不断的在Verilog和C之间复制数据。

SystemVerilog引入了DPI(Direct Programming Interface),能够更简洁的连接C,C++或者其他非Verilog的编程语言。
只要使用import声明和使用,导入一个C子程序,就可以像调用SystemVerilog中的子程序一样来调用它。

SystemVerilog和C语言之间传递的最基本的数据类型是int,双状态的32位的数据类型,

通过import声明定义C任务和函数的原型,带有返回值的C函数被映射成一个systemverilog的函数(function),

void类型的C函数被映射为一个systemverilog的任务(task)或者void 函数(function)

通过“DPI-C”引入的C函数,可以直接在function中调用,但是只在该DPI被声明的空间内有效

所以可以在package中将所有的DPI函数在做封装,打包为function。然后在需要的地方,import package。

使用关键字DPI-C表示,使用压缩值(packed)的方式来保存数据类型。

import "DPI-C" function int factorial(input int i);

program automatic test;

initial  begin

for(int i=1;i<=10;i++)

$dispaly("%0d != %0d",i,factorial(i));  //像调用正常的function int一样。

end                                                       //凡是可以声明function的地方,module,program,interface,package都可以import DPI

endprogram

如果C函数名和SystemVerilog中的命名冲突,可以在import导入时,赋予新的函数名。

import "DPI-C" function void test();  //将C中的test函数,import进来,变为SV中的void function

import "DPI-C" test=function void my_test();  //将C中的test函数,修改名字为my_test。

通过DPI传递的每个变量都有两个相匹配的定义,一个在SystemVerilog中,一个在C语言中。 在使用中必须,确认使用的是兼容的数据类型。

C输出数据给SV,只能通过指针的方式,输出。所以输出数据也是在SV中建立空间,然后在C中得到指针,将值写进去,这样C的内存空间的

控制不会影响到SV端。

SystemVerilog                         C(输入)                         C(输出)

byte                                    char                            char*

short int                             short int                        short int*

int                                      int                                int*

longint                             long long int                    long int*

real                                  double                            double*

string                              const char*                       char**

string[N]                         const char**                     char**

bit                            svBit/unsigned char       svBit*/unsigned char   //注意在输出时,将不需要的高位屏蔽掉

logic/reg                     svLogic/unsigned char   svLogic*/unsigned char*  //注意在输出时,将不需要的高位屏蔽掉

bit[N:0]                      const svBitVecVal*              svBitVecVal*   //注意在输出时,将不需要的高位屏蔽掉

reg[N:0]                      const svLogicVecVal*          svLogicVecVal*   //注意在输出时,将不需要的高位屏蔽掉

open array[]             const svOpenArrayHandle    svOpenArrayHandle

chandle                              const void*                    void*

以上这些定义,都可以在svdpi.h中找到相应的操作函数。该头文件必须被包含到C函数实现端

由于C中都是使用packed方式来表示数据的,所以import到SV的数据,也是使用packed的方式,而且SV仿真器不会对变量中未使用的高位,自动屏蔽

所以在C语言中,需要保证这些变量的未使用的空间部分的值,也是初始化正确的。好让SV端,正确接收。

双状态变量使用svBit(实际存储空间是unsigned char)表示,双状态变量带下标使用svBitVecVal*表示

四状态变量使用svLogic(实际存储空间是unsigned char)表示,四状态变量带下标使用svLogicVecVal*表示

0---在C中对应0x0,1---在C中对应0x1,Z---在C中对应0x2,X---在C中对应0x3

logic[0:0] word 使用一对SVLogicVecVal来表示,一个域叫做aval--表示数值0/1,一个域叫做bval--表示x/z

关于DPI调入的C的函数返回值,SV LRM推荐使用small values----void,byte,shortint,int,longint,real,shortreal,chandle,string,bit,logic

不推荐使用bit[6:0]或者logic[6:0]这样的值,因为这样需要返回一个svBitVecVal或者svLogicVecVal的指针。

直接通过DPI调用C中的标准函数

import "DPI-C" function real sin(input real r);

initial $display("sin(0) = %f", sin(0.0));

被导入的C子程序,可以有多个参数或者没有参数,缺省情况下,参数的方向是input(数据从SystemVerilog流向C函数)

参数的方向也可以定义为output和inout,ref类型目前不支持。

(只表示在import语句和C环境中,经过封装之后的function,完全符合SV语法)

import "DPI-C" function int addmul(input int a, b, output int sum);

对输入的参数常常被定义为const。这样一旦对输入的变量进行写操作,C编译器就会报错。

int factorial (const int i) {}

连接C语言的例子。

#include <svdpi.h>

void counter7(svBitVecVal * o,

const svBitVecVal * i,

const svBit reset,

const svBit load)

{   static unsigned char count = 0;

if(reset)   count = 0;

else if(load)  count = * i;

else count++;

count &= 0x7F;

*o = count;

}

reset和load是一个双状态的比特信号,以svBit类型进行传递。

输入i是双状态7bit 变量,用svBitVecVal类型传递。

测试平台:

import  “DPI-C” function void counter7(output bit [6:0] out,

input bit [6:0] in,

input bit reset, load);

program  automatic  counter;

bit[6:0]  out, in;

bit  reset, load;

initial  begin

$monitor("SV: out=% 3d, in =%3d, reset = %0d, load = %0d\n", out,in,reset,load);

reset = 0;

load = 0;

in = 126;

out = 42;

counter7(out, in, reset, load);

end

endprogram

如果reset/load使用svLogic的类型,C程序中需要检查X、Z的状态

if(reset & 0x02) //检查变量bval中的X/Z

printf("reset val include X/Z value");

如果counter使用svLogicVal类型,C程序中检查X、Z的状态

counter.aval = inst->cnt;

counter.bval = 0;   //aval与bval实际存在一个logicval的结构体中

chandle类型允许在System Verilog中存储一个C/C++的指针,指向一段地址,来保存一些常量。

typedef struct{unsigned char cnt;} c7;

void *counter7_new() { c7* c=(c7*) malloc (sizeof(c7));

c-> cnt = 0;

return c;}

void counter7(c7* inst, ...)

测试平台:

import “DPI-C” function  chandle  counter7_new();

import "DPI-C" function void counter7(input chandle inst, ...);

program automatic test;

initial begin

chandle inst1;

inst1 = counter7_new();

counter7(inst1,...);

end

endprogram

C与SV之间传递数组,可以是openarray,也可以是定宽数组。

定宽数组:

void fib(svBitVecVal data[20]) {

}

import "DPI-C" function void fib(output bit[31:0] data[20])

program automatic test;

bit[31:0] data[20];

initial begin

fib(data);

end

endprogram

openarray型指针,需要在C端通过svGetArrayPtr来得到来自SV的动态数据的地址

其他类型的指针,可以直接在C中通过*ptr来赋值或调用。

void fib_oa(const svOpenArrayHandle data_oa) {

}

import "DPI-C" function void fib_ca(output bit[31:0]data[])

program automatic test;

bit[31:0] data[20],r;

fib_ca(data);

endprogram

openarray定义的查询方法:

int svSizeOfArray(h): 以字节计量的数组大小

int svSize(h,d): 维数d的元素总个数

int svLeft(h,d): 维数d的左边界, svLeft(h,1)一维数组的左边界,svleft(h,2)二维数组的左边界

int svRight(h,d): 维数d的右边界,=

openarray定义的定位函数:

void * svGetArrayPtr(h): 整个数组的存储位置

void *svGetArrElemPtr(h,i1,...): 数组中的一个元素

void *svGetArrElemPtr1(h,i1): 一维数组中的一个元素

void *svGetArrElemPtr2(h,i1,i2): 二维数组中的一个元素

使用DPI也可以将SV的function/task export到C环境中

module  block;

export "DPI-C" function sv_display;

....

endmodule

extern void sv_display();

void c_display() {

sv_display();

}

SV通过DPI调用C的更多相关文章

  1. runv start container 流程分析

    1.runv/start.go func startContainer(context *cli.Context, container, address string, config *spec.Sp ...

  2. ios9API基础知识总结(二)

    UIAlertView(警告框) UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"标题" message:@&qu ...

  3. mshadow的原理--MXNet

    mshadow的原理--MXNet 这文章主要解释了表达式模板的工作原理(也是mshadow的主要原理),文章的前半部分是翻译自exp-template/README.md.我们会解释它为什么会影响编 ...

  4. python-nmap的函数学习

    简介 python-nmap是一个使用nmap进行端口扫描的python库,它可以很轻易的生成nmap扫描报告,并且可以帮助系统管理员进行自动化扫描任务和生成报告.同时,它也支持nmap脚本输出. 可 ...

  5. 羽翼metasploit第一,二季学习笔记

    -----------------第一季-------------------- 启动Metasploit:msfconsole 升级和更新:./msfupdate 直接退出:exit 退回上一级:q ...

  6. run_test() 验证平台的入口

    Run,just run!    ——阿甘正传   一个简单的例子: module tb_top; dut u_dut (); initial begin run_test(); end config ...

  7. Cracking Digital VLSI Verification Interview 第四章

    目录 Hardware Description Languages Verilog SystemVerilog 对Cracking Digital VLSI Verification Intervie ...

  8. 黑马毕向东Java基础知识总结

    Java基础知识总结(超级经典) 转自:百度文库 黑马毕向东JAVA基础总结笔记    侵删! 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部 ...

  9. 《果壳中的C# C# 5.0 权威指南》 - 学习笔记

    <果壳中的C# C# 5.0 权威指南> ========== ========== ==========[作者] (美) Joseph Albahari (美) Ben Albahari ...

随机推荐

  1. CSS盒子模型(简要了解)

    CSS中, Box Model叫盒子模型(或框模型),Box Model规定了元素框处理元素内容(element content).内边距(padding).边框(border) 和 外边距(marg ...

  2. postgre

    切换用户:su postgres 启动:psql 查看有哪些数据库: \l 切换到数据库air: \c air 列出数据库中所有表: \d 列出指定表的所有字段信息: \d+ dag 或者 \d da ...

  3. java中使用jdbc配置连接串时mysql 5.6与5.7版本“编码”参数有区别!

    在mysql5.6中 java程序使用jdbc时链接字符串应该使用?characterEncoding=utf-8,而5.7版本可以省略,否则可能会有相关的语句执行结果出错! String drive ...

  4. sed命令 windows与linux换行

    Linux的Bash命令中有一个sed操作,SSD的create_list.sh中有用到这个操作: 结合着下面这个解释: 也就是删除所有行里面的以VOC2007/Annotations/(这里的\代表 ...

  5. java安全删除一个文件,防止工具恢复数据

    解决移动端文件删除的安全问题:file.delect()   Java 确保安全删除某个文件 http://outofmemory.cn/code-snippet/14222/Java-securit ...

  6. 谷歌浏览器安装octotree插件

    Octotree Chrome安装与使用方法 Octotree Chrome作用: 主要使你在github查看项目时可以清晰明了的看到项目的结构以及具体代码,使下载代码更具有目的性,减少不必要代码的下 ...

  7. java取得汉字拼音(pinyin4j)

    jar包:pinyin4j.jar 基本用法: String[] pinyin = PinyinHelper.toHanyuPinyinStringArray('重'); 例如“重”字,该方法返回一个 ...

  8. C语言编程练习

    1.编程序实现求1-1000之间的所有奇数的和并输出. 解法1: int sum=0; for(int i=1;i<=1000;i++){ sum+=i%2?i:0; } printf(&quo ...

  9. php使用solr全文搜索引擎

    前言 本来以为网上已经有了类似博文,不想重复,可是一圈搜下来,都是一些内容不甚明了的文章,或者solr版本太过老,参考价值不高,更有甚者,直接拷贝的别人的内容.一篇博客,各大平台都能看到,也不见转载链 ...

  10. git pull和push冲突

    http://blog.csdn.net/matrix_laboratory/article/details/18034509 问题描述 1 有人改动了 文件A.java,提交到git 2 我没有pu ...