进行数字设计时,经常会遇到特殊的情况,Verilog 中的任务和函数已经不能满足仿真需求,需要自定义一些系统任务和函数。编程语言接口(PLI, Program Language Interface)提供了一套接口子程序,用于访问设计内部的数据结构,并可以提取仿真环境信息。用户可以调用这些子程序,自定义系统任务和系统函数,与设计内部数据以及 Verilog 仿真器环境进行交互。
PLI 功能
通俗来讲,Verilog PLI 提供了一套 C 语言函数, 设计人员可以调用这些集成函数编写软件 C 程序。RTL 编译时,将编写的软件程序也集成到仿真环境中。仿真运行时,通过系统任务调用的方式,就可以动态的去访问仿真中的数据结构。这种访问是双向的,不仅可以从仿真器的数据结构中读取信息, 还能修改数据结构的信息。
PLI 的功能是十分强大的,其用途只局限于设计人员的想象力。
- PLI 允许用户用 C 编写自定义的系统任务和函数,可以完成用 Verilog 不能完成的复杂操作。
- 一些应用软件,例如文件读写工具,延迟计算工具,也可以用 PLI 编写。
- PLI 可提取设计信息,例如访问层次、互连情况、以及特定类型的逻辑元件数量等。
- PLI 可用于编写专用的输出显示程序,例如一些专用的波形观测器,生成一些逻辑互连、层次、数据波形等信息。
- PLI 可完成繁琐的监测任务或激励任务。
- PLI 能控制仿真的过程,例如暂停、退出,便于调试。
- PLI 还可以扩展的用途有,RAM/ROM程序下载工具,功耗分析,CModel 接口, 协同仿真环境……
这里总结下 PLI 经常使用的功能:
- (1) 实现 CModel 与 Verilog 模型的共同仿真。对于比较复杂的系统,开发者经常需要先制作一个能够正常工作的用 C 语言描述的模型,然后逐模块地将其改写为 Verilog 表述。
- (2) 产生测试激励,或直接进行验证。对于数据量比较大的输入激励,或比较复杂的控制输入,以及特定环境下的数据验证,PLI 实现比 Verilog 更具有优势。
- (3) 捕获仿真过程和结果,并以用户易于接受的方式输出。例如一些编解码的模块,使用用户自定义的显示效果,更容易调试。
- (4) 软硬件联合仿真。例如设计中包含 CPU 实体,可以将软件编译成机器码加载到相应的 ROM中进行联合仿真。
PLI 版本
PLI 的发展主要经历了 3 代。
1985-TF 接口
第一代被称为任务/函数(Task/Function)接口,简称 TF 接口。TF 接口包含一套 C 语言函数库,均以 tf_ 为前缀,定义在 veriuser.h 中。这些 C 函数一般称为 TF 子程序,主要包括用户自定义任务和函数、实用函数、回调机制和数据写输出。
1989-ACC 接口
第二代被称为存取(Access)接口,简称 ACC 接口。ACC 接口中的函数均以 acc_ 为前缀,定义在 acc_user.h 中。ACC 子程序主要用于访问和修改 Verilog 描述的多种对象。ACC 库函数是 TF 库函数的叠加,而非替换。
一般 PLI 接口特指是 TF 和 ACC 接口。
1995-VPI 接口
第三代被称为过程接口(Verilog Process Interface),简称 VPI 接口。VPI 子程序是 TF 和 ACC 子程序功能的合集,定义在 vpi_user.h 中。
相对于 PLI 子程序又多又乱,VPI 尤显精炼。由于 PLI 诞生之初,没有统一的标准,完全是在实践中发展,导致常用的 PLI 库函数有近百个,写程序时基本都要查手册。
而 VPI 是根据一定的标准统筹规划制定的,融入了很多面向对象的思想,库函数精简度远超 PLI。但是 VPI 结构比较复杂,不容易上手。VPI 最大的弱点还是对仿真器的支持并不友好。
2003-SystemVerilog 与 DPI
作为 Verilog 的扩展,2003 年 SystemVerilog 标准发布,支持更多形式的仿真。
DPI 接口(Direct Procee Interface)成为软件与 SystemVerilog 交互的接口,目前占主流。
一般情况下,使用 PLI 的 TF 和 ACC 接口就能满足仿真需求了。本章只对 TF 和 ACC 接口进行简单介绍。其他接口待那个少年学成之日,再一一分享给大家。
PLI 使用
通过编写系统任务和系统函数, 用户能够用 PLI 和 C 程序扩展 Verilog 语言。这些用户定义的系统任务和函数的名称必须以美元符号 "$" 开头。此时 Verilog 里面的任务相当于一个子程序。当调用任务时,仿真器的执行流程跳转到子程序,完成任务后执行流程返回。Verilog 任务并不返回数值,但是可以有输入、输出和双向的形参。
Verilog 里面的函数跟大多数语言里面的函数一样。 当调用函数时,它运行一套指令,然后返回一个数值给调用它的指令。
PLI 流程
使用 PLI 接口完成用户自定义系统任务的基本流程如下所示。
下面以简单的系统任务 $hello_zhishitu 为例进行说明。该系统任务被调用时,会输出一行字符串 "Hello Runoob!"。
PLI 编写系统任务
用 C 语言描述的打印程序如下所示,文件命名为 hello_zhishitu.c 。
为说明 PLI 使用的一般流程,此程序并没有调用 TF/ACC 子程序。
实例
#include "stdio.h" //不包含 PLI 库子程序
int hello_zhishitu(){
printf("Hello Runoob! \n");
}
#include "stdio.h" //不包含 PLI 库子程序
int hello_zhishitu(){
printf("Hello Runoob! \n");
}
PLI 连接仿真器
以 VCS 使用为例,编译或创建 VCS 编译时需要的与 C 相关的文件。
对上述 hello_zhishitu.c 进行简单的编译,输出 hello_zhishitu.o 文件。注意相对路径。
gcc -c ../tb/hello_zhishitu.c
创建 VCS 可识别的链接 table 文件,文件命名为 hello_zhishitu.tab, 内容如下。
$hello_zhishitu call=hello_zhishitu
Verilog 调用系统任务
在 Verilog 中以系统任务调用的方式调用 $hello_zhishitu,描述如下。
实例
`timescale 1ns/1ps
module test ;
initial begin
#10 ;
$hello_zhishitu;
end
initial begin
forever begin
#100;
if ($time >= 10000) $finish ;
end
end
endmodule
`timescale 1ns/1ps
module test ;
initial begin
#10 ;
$hello_zhishitu;
end
initial begin
forever begin
#100;
if ($time >= 10000) $finish ;
end
end
endmodule
Verilog 编译仿真
对 RTL 和 编写的 PLI 中间文件进行编译。表明要链接 PLI 库中的表文件时,需要用 "-P" 参数指定。例如该仿真中应该在 VCS 命令行中增加如下参数(注意相对路径):
-P ../tb/hello_zhishitu.tab hello_zhishitu.o
仿真结果中可以看到打印的信息,截图如下。