22

LJgibbs · 2020年04月23日

Modelsim 重度使用者的故事:验证设计,软件与硬件的故事

在开发 Verilog IP 的过程中,比如图像处理或者密码学的 IP 。验证功能总是很重要的一步,也很是伤脑筋的。

这些 IP 最靠谱的验证方法往往是和软件结果进行对比。比如图像处理 IP 和 OpenCV 或者 Matlab 结果对比。密码学 IP 和事实上的标准软件 Openssl 对比。问题出在怎么对比上,下面欢迎我朋友的现身说法。

I

记得那是一次面试 ...
面试官:那你是怎么在 Modelsim 上验证你的 SM3 算法 IP 的呢?
朋友:和软件结果对比。具体怎么对比?还能怎么对比,一个一个眼睛看呗。
面试官:。。。你视力真好(我看你是吃饱了撑的 ^\_^)

II

后来我的朋友机智了一些,他使用 $display 将仿真中的结果打印出来,比如这样

integer file;
initial begin:inital_file

file = $fopen("result_frm_v.txt","w");

always@(*) begin        
    if(valid)
    begin
        $fdisplay(file,"%32h",result);
    end
end

然后把软件结果也打印出来,打开 BeyondCompare 一比,成了。

III

再后来,他觉得这样太麻烦了,我们为什么不能在 Modelsim 里直接调用 C 语言呢?
好,搜索引擎走起,他发现了一个叫做  DPI  的东西,好像比 VPI ,PLI 都看起来比较方便的样子。他找到了一些文章:

  1. https://www.cnblogs.com/studyforever/p/5132452.html
  2. https://blog.csdn.net/immeatea\_aun/article/details/80569938?depth\_1-utm\_source=distribute.pc\_relevant.none-task-blog-BlogCommendFromBaidu-4&utm\_source=distribute.pc\_relevant.none-task-blog-BlogCommendFromBaidu-4
  3. https://blog.csdn.net/seabeam/article/details/28868345

但它们好像都语焉不详,后来他发现 Modelsim 安装时自带的手册其实写的很清楚:
1.在开始菜单找到手册↓
图片.png
2.打开手册,选择 User Manul,我们就可以找到 Verilog Interface to C 的章节
图片.png
我 Verilog 共有 3 种访问 C 函数的接口,我们来看第三种 System Verilog DPI,因为从作者前期调研来看,DPI 似乎使用最为简单。
而且 SV 也兼容 Verilog,Modelsim 也支持 SV,所以直接用 SV 好了(但是 ISE 不支持 SV)
我们打开左栏中的 DPI Example,手册提供了一个简单的例子
hello\_c.c:

#include "svdpi.h"
#include "dpiheader.h"
int c_task(int i, int *o)
{
   printf("Hello from c_task()\n");
   verilog_task(i, o); /* Call back into Verilog */
   *o = i;
   return(0); /* Return success (required by tasks) */
}

hello.v:

module hello_top;
   int ret;
   export "DPI-C" task verilog_task;
   task verilog_task(input int i, output int o);
      #10;
      $display("Hello from verilog_task()");
   endtask
   import "DPI-C" context task c_task(input int i, output int o);   initial
   begin
      c_task(1, ret);  // Call the c task named 'c_task()'
   end
endmodule

分别是一个 C 语言文件和 v 文件(所以啊,Verilog 也可以用咯)以及操作过程。在安装目录下还有其他例子。

但我发现例子其实是在 *(D:\modeltech64\_10.2 你的安装目录)\examples\systemverilog\dpi* 路径下。

分析一下

这里例子里演示了,Verilog 和 C 语言 export 和 import 的交互接口,我们从 Verilog 的角度来看:

import C 语言函数

使用 import  ,以 context task 的形式导入了 C 语言的函数 c\_task ,并定义了这个 task (实际上的 C 语言函数),定义了 input 以及 output 端口

import "DPI-C" context task c_task(input int i, output int o);

在调用时,自然使用 verilog task 的形式:

initial
   begin
      c_task(1, ret);  // Call the c task named 'c_task()'
   end

在 C 语言中 c\_task 函数的定义,打印字符串到控制台

int c_task(int i, int *o)
{
   printf("Hello from c_task()\n");
   //....
   return(0); /* Return success (required by tasks) */
}

除了导入为 task 外,C 语言函数还可以 import 为 Verilog 函数

import "DPI-C" function void c_print(int a);

Tiny Lab

由于时间关系,我没有跑官方的例子,我准备了一个只有 import ,并将参数从 Verilog 传至 C  的小实验。

  • 首先,准备 C 语言和 SV 源文件,简单地实现传参打印功能

    • C语言
//hellow.c
#include "stdio.h"

void c_print(int a)
{
     printf("hw %d!",a);
};

int main()
{
    return 0;
}
  • SV
//dvi_test_demo.sv
module dvi_demo;
int a;
//void c_print(); 为声明在 hellow.c 中的函数
import "DPI-C" function void c_print(int a);

initial begin
    a = 1;
    c_print(a);
end
endmodule

新建一个目录,把两个文件置于该目录下,比如:D:\\pro\_sv\_dvi\_test
图片.png

  • 直接打开 Modelsim,而无需从 FPGA 的工具中打开(建议直接打开)

切换至工作目录,注意使用 /

cd D:/pro_sv_dvi_test

编译 c 和 sv 代码

vlib work
vlog ./dvi_test_demo.sv
vlog ./hellow.c

启动仿真,这里的 dvi\_demo 是 SV 中的顶层模块名

vsim dvi_demo
restart -f;run 1us

注意这里要 run 一下,就可以看到打印了,成功的调用了 c 语言函数,我们传入的参数正是 1

hw 1!

好了,收工之前说几句

  • 如果修改了 SV,那么重新 vlog ./dvi\_test\_demo.sv 文件,然后 restart -f;run 1us 即可
  • 但如果修改了 C 文件,那么建议除了 vlog ./hellow.c之外,再 vsim dvi\_demo;restart -f;run 1us 会比较好,如果出现无打印的情况,建议多试几次,我也有遇到这个问题,大家可以留言交流。
  • 关于环境:win10
  • 关于版本:10.2 和 10.5 都试没什么问题

另外,说下我知道可能的问题,trouble shooting 一下

  • 未安装 gcc,如果在 Modelsim 控制台上 gcc -v 没有正确的输出,则需要安装 gcc。
  • vsim 后出现一些错误,指向一个曾经的路径。建议删除原有的 work 库后重试
推荐阅读
关注数
10604
内容数
561
FPGA Logic 二三事
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息