VPI step by step(1)

本文主要参考”The Verilog PLI Handbook(Second Edition)”, 权当读书笔记。主要针对VCS flow, 也许会穿插其他两大家工具的flow.


说在最前面

到今天为止,SV对C/Cpp的主要接口支持大多改用DPI, 也推荐使用DPI。或者直接使用UVM自带现成的DPI lib, 已经可以满足不少需求。然后类似C与汇编的关系,VPI更接近与底层Verilog与C的交互,可以很容易的取得各种仿真时的资源和状态。所以可以说因为迫不得已,有时候还得上VPI.


Hello World!

A “Hello, World!” program is traditionally used to introduce novice programmers to a programming language. —— [ wiki ]

让我们遵循传统,从hello world开始。
Hello world需要四步, 这里直接把原文例子搬运过来:

1. 定义系统task/function

第一步很简单, 起个名字,你希望在TB里怎么调用它?这里就叫$hello了:

module test;
    initial
    $hello();
endmodule

2. 实现系统task/function

看到“实现“两个字就知道这一步是核心。这一步主要完成的是Verilog里调用C的内容,因此也可以说是C的部分怎样去实现。另外,书中把这称之为calltf, 感觉这个tf是task/function的合体.下面给出具体实现:

#include 
#include 
#include “vpi_user.h”
/* ANSI C standard library */
/* ANSI C standard input/output library */
/* IEEE 1364 PLI VPI routine library */
PLI_INT32 PLIbook_hello_calltf(PLI_BYTE8 *user_data)
{
    vpi_printf(“\nHello World!\n\n”);
    return(0);
}

首先值得一提的是vpi_user.h. 这个头文件里包含了vpi的各种数据结构体,参数类型,属性以及函数原型。这部分内容可以在IEEE 1800(SV标准)的附录里找到。可以说这是每一个vpi程序必备的头文件,EDA厂商据此实现API供用户使用,具体实现就内部保密了。正因为是自定义,御三家对这个文件具体处理是不一样的,比如synopsys就没有实现vpi_get_data()这个API,理由是他们觉得不会有很多人用。但是大体上说,三家都实现了绝大部分规定的VPI,以及自己还提供扩展的API.基于vpi_user.h的实现,一般可以认为是通用的。
第二点新鲜的是PLI_INT32与PLI_BYTE8,其实就是C里的int和char类型,这里认为int是32位而char是8位。
再往下看,vpi_printf()这个函数是第一个接触到的VPI函数,和C里的printf的用法是一致的。

3.注册系统task/function

说白了就是建立VPI和Verilog之间的关联,这样TB才知道调用哪个tf. 注册内容主要包括三个方面:

  • API类型:task还是function(熟悉Verilog的你知道这句话在说什么)
  • Verilog侧API名
  • VPI侧API名

可以看出,verilog侧完全可以不叫VPI那边的名字。
在VPI中注册信息包含在s_vpi_register_systf这个结构体中,vpi_register_systf()函数使用这个结构体去注册。注册的函数都保存在VPI侧一个叫vlog_startup_routines的数组里。下面以$hello为例:

void PLIbook_hello_register()
{
    s_vpi_systf_data tf_data;

    tf_data.type        = vpiSysTask;
    tf_data.sysfunctype = 0;
    tf_data.tfname      = "$hello";
    tf_data.calltf      = PLIbook_hello_calltf;
    tf_data.compiletf   = NULL;
    tf_data.sizetf      = NULL;
    tf_data.user_data   = NULL;

    vpi_register_systf(&tf_data);
}

以上是注册的细节,在实际操作中往往不用这么麻烦–其实至今没有实验出vcs走这个flow怎样才能走通。
vcs中通常使用的方法是pli.tab文件,在这个例子里很简单:

$hello call=PLIbook_hello_calltf

nc中有类似的文件plimap.


万事俱备, 开始编译:

vcs hello_test.v +vpi -P pli.tab hello_vpi.c -full64

运行simv输出

Hello World!

参考资料

[1]: Stuart Sutherland. The Verilog PLI Handbook(Second Edition), 2002

你可能感兴趣的:(SystemVerilog)