Abstract
自行寫一個System Task,能夠接受由Verilog的reg或wire傳給C的值。

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

在此文件,將學習到
1.如何將參數從Verilog傳到C?
2.如何撰寫簡單的compiletf?
3.如何從C抓到Verilog傳來的參數?

show_value.c / C

1 #include <stdlib.h>
2 #include "vpi_user.h"
3 
4 PLI_INT32 show_value_compiletf(PLI_BYTE8 *user_data) {
5   vpiHandle systf_handle, arg_iterator, arg_handle;
6   PLI_INT32 arg_type;
7  
8   // obtain a handle to the system task instance
9   systf_handle = vpi_handle(vpiSysTfCall, NULL);
10   if (systf_handle == NULL) {
11     vpi_printf("ERROR: $show_value failed to obtain systf handle\n");
12     vpi_control(vpiFinish, 0);
13    
14     return -1;
15   }
16  
17   // obtain handles to system task arguments
18   arg_iterator = vpi_iterate(vpiArgument, systf_handle);
19   if (arg_iterator == NULL) {
20     vpi_printf("ERROR: $show_value requires 1 argument\n");
21     vpi_control(vpiFinish, 0);
22    
23     return -1;
24   }
25  
26   // check the type of object in system task arguments
27   arg_handle = vpi_scan(arg_iterator);
28   arg_type   = vpi_get(vpiType, arg_handle);
29   if (arg_type != vpiNet && arg_type != vpiReg) {
30     vpi_printf("ERROR: $show_value arg must be a net or a reg\n");
31     vpi_free_object(arg_iterator);
32     vpi_control(vpiFinish, 0);
33    
34     return -1;
35   }
36  
37   // check only 1 system task argument
38   arg_handle = vpi_scan(arg_iterator);
39   if (arg_handle != NULL) {
40     vpi_printf("ERROR: $show_value can only have 1 argument\n");
41     vpi_free_object(arg_iterator);
42     vpi_control(vpiFinish, 0);
43    
44     return -1;
45   }
46  
47   return 0
48 }
49 
50 PLI_INT32 show_value_calltf(PLI_BYTE8 *user_data) {
51   vpiHandle systf_handle, arg_iterator, arg_handle, net_handle;
52   s_vpi_value current_value;
53  
54   // obtain a handle to the system task instance
55   systf_handle = vpi_handle(vpiSysTfCall, NULL);
56  
57   // obtain hadle to system task argument
58   // compiletf has already verified only 1 arg with corret type
59   arg_iterator = vpi_iterate(vpiArgument, systf_handle);
60   net_handle = vpi_scan(arg_iterator);
61   vpi_free_object(arg_iterator);
62  
63   // read current value
64   current_value.format = vpiHexStrVal; // read a value as a string
65   vpi_get_value(net_handle, &current_value);
66   vpi_printf("Signal %s ", vpi_get_str(vpiFullName, net_handle));
67   vpi_printf("has the value %s\n", current_value.value.str);
68  
69   return 0;
70 }
71 
72 void show_value_register() {
73   s_vpi_systf_data tf_data;
74  
75   tf_data.type = vpiSysTask;
76   tf_data.tfname = "$show_value";
77   tf_data.calltf = show_value_calltf;
78   tf_data.compiletf = show_value_compiletf;
79  
80   vpi_register_systf(&tf_data);
81 }


Step 1:
撰寫compiletf,判斷由Verilog傳給C的參數是否合法

第5行

vpiHandle systf_handle, arg_iterator, arg_handle;


vpiHandle是VPI自訂的型態,為pointer to Verilog object。systf_handle為pointer to system task,arg_iterator為pointer to argument iterator,arg_handle為pointer to argument。

第8行

// obtain a handle to the system task instance
systf_handle = vpi_handle(vpiSysTfCall, NULL);
if (systf_handle == NULL) {
  vpi_printf(
"ERROR: $show_value failed to obtain systf handle\n");
  vpi_control(vpiFinish,
0);
   
 
return -1;
}


由vpi_handle()取得system task的handle,若為NULL,則顯示錯誤訊息並且結束模擬。

17行

// obtain handles to system task arguments
arg_iterator = vpi_iterate(vpiArgument, systf_handle);
if (arg_iterator == NULL) {
  vpi_printf(
"ERROR: $show_value requires 1 argument\n");
  vpi_control(vpiFinish,
0);
   
 
return -1;
}


由vpi_itrator()獲得argument iterator,為參數的集合,若為NULL,則顯示錯誤訊息並且結束模擬。

26行

// check the type of object in system task arguments
arg_handle = vpi_scan(arg_iterator);
arg_type  
= vpi_get(vpiType, arg_handle);
if (arg_type != vpiNet && arg_type != vpiReg) {
  vpi_printf(
"ERROR: $show_value arg must be a net or a reg\n");
  vpi_free_object(arg_iterator);
  vpi_control(vpiFinish,
0);
   
 
return -1;
}


檢查參數是否為reg或者wire型態,由vpi_scan()從argument iterator萃取出argument handle,再由vpi_get()獲得參數的型別做判斷,若不是wire或reg,則顯示錯誤訊息並結束模擬。

37行

// check only 1 system task argument
arg_handle = vpi_scan(arg_iterator);
if (arg_handle != NULL) {
  vpi_printf(
"ERROR: $show_value can only have 1 argument\n");
  vpi_free_object(arg_iterator);
  vpi_control(vpiFinish);
   
 
return -1;
}


由於$show_value()只允許Verilog傳入一個參數,在此判斷user是否只傳入一個參數,若由vpi_scan()抓取argument iterator還能抓到值,表示不只一個參數,則顯示錯誤訊息並結束模擬。

Step 2
撰寫calltf,讀取Verilog傳給C的參數。

由於compiletf已經驗證了參數的正確性,calltf可大膽的假設參數都已經正確。

52行

s_vpi_value current_value;


C所抓到的Verilog參數值,為一個struct。

54行

// obtain a handle to the system task instance
systf_handle = vpi_handle(vpiSysTfCall, NULL);
 
// obtain hadle to system task argument
// compiletf has already verified only 1 arg with corret type
arg_iterator = vpi_iterate(vpiArgument, systf_handle);
net_handle
= vpi_scan(arg_iterator);
vpi_free_object(arg_iterator);
 
// read current value
current_value.format = vpiHexStrVal; // read a value as a string
vpi_get_value(net_handle, &current_value);


systf_handle -> arg_iterator -> net_handle -> current_value

66行

vpi_printf("Signal %s ", vpi_get_str(vpiFullName, net_handle));
vpi_printf(
"has the value %s\n", current_value.value.str);


顯示參數值,vpi_get_str()顯示reg或wire的完整hierarchy架構名稱,並以16進位字串顯示。

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

void show_value_register() {
  s_vpi_systf_data tf_data;
 
  tf_data.type
= vpiSysTask;
  tf_data.tfname
= "$show_value";
  tf_data.calltf
= show_value_calltf;
  tf_data.compiletf
= show_value_compiletf;
 
  vpi_register_systf(
&tf_data);
}


與Hello World的差別是,多指定了compiletf部分。

Step 4:
一個簡單的Verilog counter

counter.v / Verilog

1 `timescale 1ns/1ns
2 
3 module Counter (
4   input iCLK,
5   input iRST_N,
6   output reg [7:0] oCnt
7 );
8 
9 reg [7:0] cnt;
10 
11 always@(posedge iCLK, negedge iRST_N) begin
12   if (!iRST_N)
13     oCnt <= 8'h00;
14   else
15     oCnt = oCnt + 1'b1;
16 end
17 
18 endmodule


Step 5:
Testbench中使用$show_value

counter_tb.v / Verilog

1 `timescale 1ns/1ns
2 
3 module Counter_tb;
4 
5 reg clk;
6 reg rst_n;
7 wire [7:0] cnt;
8 
9 initial begin
10   clk   = 0;
11   rst_n = 0;
12  
13   #1
14   rst_n = 1;
15  
16   #10 
17   $show_value(cnt);
18   $display("$display for cnt = %h", cnt);
19  
20   #10 
21   $show_value(cnt);
22   $display("$display for cnt = %h", cnt);
23  
24   #10 $finish;
25 end
26 
27 always #5 clk = ~clk;
28 
29 Counter counter (
30   .iCLK(clk),
31   .iRST_N(rst_n),
32   .oCnt(cnt)
33 );
34 
35 endmodule


Step 6:
使用NC-Verilog模擬

ncverilog  +access+r  Counter.v  Counter_tb.v


ncverilog: 05.40-s011: (c) Copyright 1995-2005 Cadence Design Systems, Inc.
TOOL:    ncverilog   
05.40-s011: Started on Mar 25, 2009 at 16:53:38 台北標準時間
ncverilog
    +access+r
    Counter.v
    Counter_tb.v
Recompiling(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI) reason: file '.\Counter_tb.v' is newer than expected.
    expected: Wed Mar
25 16:53:17 2009
    actual:   Wed Mar
25 16:53:34 2009
file: Counter.v
file: Counter_tb.v
    module worklib.Counter_tb:v
        errors:
0, warnings: 0
        Caching library 'worklib' (筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI). Done
    Elaborating the design hierarchy:
    Building instance overlay tables: (筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI).. Done
    Generating native compiled code:
        worklib.Counter_tb:v <0x24a5152d>
            streams:  
2, words:  1787
    Loading native compiled code:     (筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI).. Done
    Building instance specific data structures.
    Design hierarchy summary:
                         Instances  Unique
        Modules:                
2       2
        Registers:              
4       4
        Scalar wires:           
2       -
        Vectored wires:         
1       -
        Always blocks:          
2       2
        Initial blocks:         
1       1
        Simulation timescale:  1ns
    Writing initial simulation snapshot: worklib.Counter_tb:v
Loading snapshot worklib.Counter_tb:v (筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI)(筆記) 如何將參數從Verilog傳到C? (SOC) (Verilog) (Verilog PLI).. Done
ncsim> source
"C:/Program Files/Cadence Design Systems/IUS/tools/inca/files/ncsimrc"
ncsim> run
Signal Counter_tb.cnt has the value
01
$display for cnt
= 01
Signal Counter_tb.cnt has the value
02
$display for cnt
= 02
Simulation complete via $finish(
1) at time 31 NS + 0
.\Counter_tb.v:
24   #10 $finish;
ncsim> exit
TOOL:    ncverilog   
05.40-s011: Exiting on Mar 25, 2009 at 16:53:41 台北標準時間  (total: 00:00:03)


完整程式碼下載
pli_show_value.7z

Reference
The Verilog PLI Handbook Ch.1

相关文章: