一种Verilog代码调用C/C++函数的机制

时间:2022-09-22 08:49:12

Verilog PLI(Programming Language Interface )是一种Verilog代码调用C/C++函数的机制。它能让Verilog像调用一些系统调用(如$display/$stop/$random)一样调用用户编写的C/C++函数,这样我们可以用C/C++语言开始自己的system task/function, 来实现用verilog不太方便的功能,并与外界建立了联系。
PLI可以完成如下功能:

  • 功耗分析

  • 代码覆盖率工具

  • 修改Verilog仿真数据结构(如修改为更精确的延时,即sdf反标)

  • 自定义输出显示

  • 联合仿真

  • 设计的调试功能

  • 仿真分析

  • 加速仿真的C模型接口

  • Testbench建模

Verilog PLI提供了一些访问verilog内部数据结构的

  • 任务功能程序集 (TF routines): 大部分以tf_开头,主要用于一些用户定义系统任务和函数变量的操作,工具函数(比如设置回调函数和写数据到输出)

  • 访问程序集 (ACC routines): 第二代PLI. 所有以acc_开头。提供了对象导向的对SV结构的访问。主要用于访问和修改信息,比delay value, logic value. ACC routines和TF routines有部分重复。

  • 验证过程接口程序集 (VPI routines): 第三代PLI。大部分以vpi_开头。提供了对象导向的对SV结构, 行为, assertion, coverage 对象的访问。 它包含了八戒影院TF和ACC routines的所有功能。

2. 用户定义task/function命名

规则如下:

  • 第一个字符必须是$

  • 剩下的字符可以是字母, 数字,下划线或$

  • 大小写敏感

  • 名字可以任意长度

3. 用户定义task/function的参数

例子:

$get_vector("test_vector.pat", input_bus);

一组PLI routines可以用于PLI程序来读/写这些参数

4. task/function

  • 用户定义的task可以用于SV task能使用的任何地方

  • 用户定义的function可以用于SV task能使用的任何地方, 可以返回值, 长度由用户提供的sizetf确定

5. 用户提供的PLI application

这类C函数不是独立的C程序,而是被Link到工具里,当用户定义的task/function被调用时,他们可能会被调用

6. PLI include文件

定义了

  • 常数

  • struct

  • 数据

这些文件是

  • vpi_user.h

  • sv_vpi_user.h

7. NC Example

一种Verilog代码调用C/C++函数的机制

Files

test.v

module test;
wire a, b, c;
initial
begin
$module_info;
end
pipe p1 (a, b, c);
//stimuli
//monitor response
endmodule

pipe.v

module pipe ( out, in, clk );
output out; reg out;
input in, clk;
always @ (in)
@ (posedge clk)
out <= repeat (2) @ (posedge clk) in;
endmodule

mod_info.c

#include <stdio.h>
#include "vpi_user.h"
#include "vpi_user_cds.h"

void module_info()
{
vpiHandle moditH, topmodH;
moditH = vpi_iterate(vpiModule, NULL);
if(!moditH) {
vpi_printf(" Error: no modules in the design\n");
}
while (topmodH = vpi_scan(moditH)) {
vpi_printf("Top module Full Name: %s\n",
vpi_get_str(vpiFullName, topmodH));
vpi_printf(" Top module Name: %s\n", vpi_get_str(vpiName, topmodH));
}
}
void register_my_systfs()
{
s_vpi_systf_data task_data_s;
p_vpi_systf_data task_data_p = &task_data_s;
task_data_p->type = vpiSysTask;
task_data_p->tfname = "$module_info";
task_data_p->calltf = (int(*)()) module_info;
task_data_p->compiletf = 0;
vpi_register_systf(task_data_p);
}

pli.map

$module_info call = module_info

vpi_user.c

#include <stdarg.h>
#include "vpi_user.h"
#include "vpi_user_cds.h"

extern void register_my_systfs();

void (*vlog_startup_routines[VPI_MAXARRAY])() =
{
register_my_systfs,
0 /*** final entry must be 0 ***/
};

RUN

有三种方法可以在NC上运行,但第一种没试通

方法一 Using the irun Utility

irun test.v pipe.v module_info.c -loadvpi :module_info

实测在运行时会找不到$module_info

方法二 Using a PLI/VPI Map File

plimap文件见上面

irun test.v pipe.v mod_info.c -plimapfile pli.map -gui

在运行时刻加载-plimapfile
或者可以elab时加载

irun test.v pipe.v mod_info.c -afile pli.map -gui

方法三 Associating C Functions with a New System Task

  • 用C function来注册你的VPI程序

  • 初始化一个s_vpi_systf_data结构

  • 调用vpi_register_systf()

  • 向simulator提供注册函数的名字

typedef struct t_vpi_systf_data
{
int type;
int sysfunctype;
char *tfname;
int (*calltf)();
int (*compiletf)();
int (*sizetf)();
char *user_data;
} s_vpi_systf_data, *p_vpi_systf_data;

运行命令如下:

gcc -fPIC -c -o vpi_user.o vpi_user.c mod_info.c -I${IES_HOME}/tools/include -I${IES_HOME}/tools/inca/include
gcc -shared -fPIC -o libvpi.so vpi_user.o

irun -c test.v pipe.v
irun -64bit -R

工具会自动加载libvpi.so
或者

gcc -fPIC -shared -o libmyvpi.so vpi_user.c mod_info.c -I${IES_HOME}/tools/include -I${IES_HOME}/tools/inca/include
ncvlog test.v pipe.v
ncelab -access +rw test -loadvpi libmyvpi:register_my_systfs
ncsim test -input

对于PLI, 使用-sv_lib是不管用的

gcc -fPIC -shared -o libmyvpi.so vpi_user.c mod_info.c -I${IES_HOME}/tools/include www.rcsx.org -I${IES_HOME}/tools/inca/include
irun -c test.v pipe.v
irun -R -64bit -sv_lib libmyvpi.so

会报错:

 
irun(64): 15.10-s020: (c) Copyright 1995-2016 Cadence Design Systems, Inc. 
Loading snapshot worklib.test:v .................... Done
$module_info;
|
ncsim: *E,MSSYSTF (./test.v,5|17): User Defined system task or function ($module_info) registered during elaboration