(原創) 如何使用C開發Verilog System Task/Function? (SOC) (Verilog) (Verilog PLI)

Abstract
本文介紹使用C開發Verilog System task/function,以彌補Verilog功能的不足。

Introduction
使用環境 : Cadense NC-Verilog 5.4 + Visual C++ 6.0

Verilog PLI(Programming Language Interface)是Verilog所提供的機制,我們可以使用C語言開發自己的system task/function,以彌補在Verilog撰寫testbench的不足。

在此文件,將學習到:
1.如何在Verilog呼叫C function?
2.如何撰寫簡單的calltf routine與register function?
3.如何在Windows平台使用Cadence NC-Verilog編譯與連結?

如下圖所示,當simulator執行自己開發的system task時,會轉而執行C的function,執行完再回到Verilog。

pli_flow

使用C開發Verilog system task的流程如下圖所示:

pli_hello_world01

Step 1:
建立C function

Step 2:
建立C function與Verilog system task的連結資料

hello_world.c / C

1 #include <stdio.h>    // define NULL, printf()
2 #include "vpi_user.h" // required by VPI application
3 
4 // my own C function for Verilog
5 PLI_INT32 hello_world(PLI_BYTE8 *user_data) {
6   vpi_printf("Hello World from C!!\n");
7  
8   return 0;
9 }
10 
11 // defined in vpi_user.h
12 /*
13 typedef struct t_vpi_systf_data {
14   PLI_INT32 type;                       // vpiSysTask, vpiSysFunc
15   PLI_INT32 sysfunctype;                // vpiSysTask, vpi[Int,Real,Time,Sized, SizedSigned]Func
16   PLI_BYTE8 *tfname;                    // first character must be `$'
17   PLI_INT32 (*calltf)(PLI_BYTE8 *);
18   PLI_INT32 (*compiletf)(PLI_BYTE8 *);
19   PLI_INT32 (*sizetf)(PLI_BYTE8 *);     // for sized function callbacks only
20   PLI_BYTE8 *user_data;
21 } s_vpi_systf_data, *p_vpi_systf_data;
22 */
23 
24 // associating C function with new verilog system task
25 // you can use your favorite function name
26 void register_my_systfs() {
27   s_vpi_systf_data tf_data; // defined in vpi_user.h
28  
29   tf_data.type   = vpiSysTask;      // system task
30   tf_data.tfname = "$hello_world"// name of system task
31   tf_data.calltf = hello_world;     // C function name
32   tf_data.compiletf = NULL;         // no compiletf routine
33  
34   vpi_register_systf(&tf_data);     // register system task to verilog
35 }


第2行

#include "vpi_user.h" // required by VPI application


寫PLI一定要include。

第4行

// my own C function for Verilog
PLI_INT32 hello_world(PLI_BYTE8 *user_data) {
  vpi_printf(
"Hello World from C!!\n");
 
 
return 0;
}


自己的C function,僅簡單的顯示Hello World。由於struct s_vpi_systf_data規定自訂的C function的signature必須為PLI_INT32 (*calltf)(PLI_BYTE8 *),所以依照其規定宣告hello_world型別。

24行

// associating C function with new verilog system task
// you can use your favorite function name
void register_my_systfs() {
  s_vpi_systf_data tf_data;
// defined in vpi_user.h
 
  tf_data.type  
= vpiSysTask;      // system task
  tf_data.tfname = "$hello_world"// name of system task
  tf_data.calltf = hello_world;     // C function name
  tf_data.compiletf = NULL;         // no compiletf routine
 
  vpi_register_systf(
&tf_data);     // register system task to verilog
}


建立C function與Verilog system task的連結資料,s_vpi_systf_data定義在vpi_user.h,其完整定義如下:

typedef struct t_vpi_systf_data {
  PLI_INT32 type;                      
// vpiSysTask, vpiSysFunc
  PLI_INT32 sysfunctype;                // vpiSysTask, vpi[Int,Real,Time,Sized, SizedSigned]Func
  PLI_BYTE8 *tfname;                    // first character must be `$'
  PLI_INT32 (*calltf)(PLI_BYTE8 *);
  PLI_INT32 (
*compiletf)(PLI_BYTE8 *);
  PLI_INT32 (
*sizetf)(PLI_BYTE8 *);     // for sized function callbacks only
  PLI_BYTE8 *user_data;
} s_vpi_systf_data,
*p_vpi_systf_data;


register_my_systfs() function主要的目的在於將s_vpi_systf_data struct填滿, 名稱不一定要取register_my_systfs,可以自行命名。

29行

tf_data.type   = vpiSysTask;               // system task


定義為System Task。

30行

tf_data.tfname = "$hello_world";           // name of system task


定義Verilog system task名稱

31行

tf_data.calltf = hello_world;     // C function name


指定自己寫的C function名稱,為function pointer,為了callback使用。

32行

tf_data.compiletf = NULL;         // no compiletf routine


由於沒用到compiletf,所以設定為NULL。

34行

vpi_register_systf(&tf_data);     // register system task to verilog


註冊新的system task。

Step 3:
在simulator註冊新Verilog system task

複製C:\Program Files\Cadence Design Systems\IUS\tools\src\vpi_user.c到目前目錄,將vpi_user.c修改如下:

1 /*
2  * |-----------------------------------------------------------------------|
3  * |                                                                       |
4  * |   Copyright Cadence Design Systems, Inc. 1985, 1988.                  |
5  * |     All Rights Reserved.       Licensed Software.                     |
6  * |                                                                       |
7  * |                                                                       |
8  * | THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF CADENCE DESIGN SYSTEMS |
9  * | The copyright notice above does not evidence any actual or intended   |
10  * | publication of such source code.                                      |
11  * |                                                                       |
12  * |-----------------------------------------------------------------------|
13  */
14 
15 /*
16  * |-------------------------------------------------------------|
17  * |                                                             |
18  * | PROPRIETARY INFORMATION, PROPERTY OF CADENCE DESIGN SYSTEMS |
19  * |                                                             |
20  * |-------------------------------------------------------------|
21  */
22 
23 #include <stdarg.h>
24 #include "vpi_user.h"
25 #include "vpi_user_cds.h"
26 
27 
28 /* extern void setup_test_callbacks();*/
29 
30 /* ----------------------------------------------------------------
31 The following is an example of what should be included in this file:
32 
33 extern void setup_my_callbacks(); <-- Add a declaration for your routine.
34 
35 void (*vlog_startup_routines[])() =
36 {
37     $*** add user entries here ***$
38 
39   setup_my_callbacks, <-- Add your routine to the table.
40 
41   0 $*** final entry must be 0 ***$
42 
43 };
44 ------------------------------------------------------------------ */
45 
46 extern void register_my_systfs();
47 
48 void (*vlog_startup_routines[VPI_MAXARRAY])() =
49 {
50   register_my_systfs,
51   0 /*** final entry must be 0 ***/
52 };


46行

extern void register_my_systfs();


使用extern宣告在hello_world.c的register_my_systfs。

48行

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


設定simulator啟動時,載入PLI的array,注意最後一個element必須為0。

Step 4:
使用PLI Wizard產生Dynamic Link Library (libvpi.dll)

啟動PLI Wizard

開始->程式集->Cadence Design Systems->Design & Verification->PLI Wizard

File -> New Session

pli_hello_world02

選擇VPI Application與libvp

pli_hello_world03

加入hello_world.c,vpi_user.c會自動抓進來

pli_hello_world04

加入VC6的include path: C:\Program Files\Microsoft Visual Studio\VC98\Include

選擇C語言

pli_hello_world05

按Finish完成

pli_hello_world06

選(Y)

pli_hello_world07

按Close離開

pli_hello_world08

File -> Exit離開PLI Wizard

Step 5:
設定libvpi.dll路徑

在Path環境變數加上libvpi.dll的路徑,注意必須加在C:\Program Files\Cadence Design Systems\IUS\tools\bin;C:\Program Files\Cadence Design Systems\IUS\tools\lib;C:\Novas\Debussy\bin;之前,否則PLI Wizard啟動會有問題。

設定好後須登出在登入,path才會生效。

若只是為了測試,可將libvpi.dll放在與*.v同目錄下即可。

Step 6:

在Verilog使用新的system task

hello_world.v / Verilog

1 module hello_world;
2 
3 initial begin
4   $hello_world;
5   #10 $finish;
6 end
7 
8 endmodule


Step 7:
執行NC-Verilog

ncverilog +access+r hello_world.v


pli_hello_world09

完整程式碼下載
pli_hello_world.7z

Conclusion
PLI在Verilog的IEEE標準中有明確定義,但如何compiling與linking方面,就與simulator與OS有關,IEEE標準並沒有加以定義。本文雖然只是一個小小的Hello World,已經展示了Verilog PLI如何在Windows平台與Cadence NC-Verilog compiling與linking,並看到Verilog如何呼叫一個C的function。

posted on 2009-03-25 21:38 真 OO无双 阅读(...) 评论(...) 编辑 收藏

导航

统计