(原創) 如何使用Verilog實現split()? (SOC) (Verilog PLI)

Abstract
嚴格來說,並不是使用Verilog實現split(),而是借由Verilog PLI,在Verilog能夠"使用"split(),將string轉成array。

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

(筆記) 如何使用C語言實現split()? (C/C++) (C) (JavaScript)中,我們已經可以在C語言中實現split(),那在Verilog呢?Verilog並不擅長string方面的處理,既然C語言可以實現,借由Verilog PLI,在Verilog也能有split()的功能。

split_vpi.c / C 

  1 /* 
  2 (C) OOMusou 2009 http://oomusou.cnblogs.com
  3 
  4 Filename    : split_vpi.c
  5 Compiler    : VC++ 6.0
  6 Description : $split() for Verilog
  7 Release     : 05/09/2009 1.0
  8 */
  9 
10 #include <stdlib.h> // NULL, malloc(), free()
11 #include <string.h> // strcpy(), strtok()
12 #include <stdio.h> 
13 #include "vpi_user.h"
14 
15 // ltrim function
16 char *ltrim (char *string, char junk) {
17   char* original = string;
18   char *p = original;
19   int trimmed = 0;
20   do {
21     if (*original != junk || trimmed) {
22       trimmed = 1;
23       *p++ = *original;
24     }
25   } while (*original++ != '\0');
26  
27   return string;
28 }
29 
30 // sizetf routine
31 PLI_INT32 split_sizetf(PLI_BYTE8 *user_data) {
32   return (32); // $split() returns 32-bit value
33 }
34 
35 // compiletf routine
36 PLI_INT32 split_compiletf(PLI_BYTE8 *user_data) {
37   vpiHandle systf_handle, arg_iterator, arg_handle;
38   PLI_INT32 arg_type;
39   int err_flag = 0;
40  
41   do { // group all tests, so can break out of group on error
42     // obtain a handle to the system task instance
43     systf_handle = vpi_handle(vpiSysTfCall, NULL);
44     if (systf_handle == NULL) {
45       vpi_printf("ERROR: $split failed to obtain systf handle\n");
46       err_flag = 1;
47       break;
48     }
49    
50     // obtain iterator to the system task argument   
51     arg_iterator = vpi_iterate(vpiArgument, systf_handle);
52     if (arg_iterator == NULL) {
53       vpi_printf("ERROR: $split requires 3 arguments; has none\n");
54       err_flag = 1;
55       break;
56     }
57    
58     // check the type of 1st argument
59     arg_handle = vpi_scan(arg_iterator);
60     arg_type = vpi_get(vpiType, arg_handle);
61     if ((arg_type != vpiMemory)) {
62       vpi_printf("ERROR: $split arg1 must be memory or variable array\n");
63       err_flag = 1;
64       break;
65     }
66    
67     // obtain a handle of 2nd argument
68     arg_handle = vpi_scan(arg_iterator);
69     if (arg_handle == NULL) {
70       vpi_printf("ERROR: $split requires 2nd argument\n");
71       err_flag = 1;
72       break;
73     }
74    
75     // check the type of 2nd argument
76     arg_type = vpi_get(vpiType, arg_handle);
77     if ((arg_type != vpiReg) && (arg_type != vpiNet) && (arg_type != vpiConstant)) {
78       vpi_printf("ERROR: $split arg2 must be reg or net or constant\n");
79       err_flag = 1;
80       break;
81     }
82    
83     // obtain a handle of 3rd argument
84     arg_handle = vpi_scan(arg_iterator);
85     if (arg_handle == NULL) {
86       vpi_printf("ERROR: $split requires 3rd argument\n");
87       err_flag = 1;
88       break;
89     }
90    
91     // check the type of 3nd argument
92     arg_type = vpi_get(vpiType, arg_handle);
93     if ((arg_type != vpiReg) && (arg_type != vpiNet) && (arg_type != vpiConstant)) {
94       vpi_printf("ERROR: $split arg3 must be reg or net or constant\n");
95       err_flag = 1;
96       break;    
97     }
98    
99     // check too many argument
100     arg_handle = vpi_scan(arg_iterator);
101     if (arg_handle != NULL) {
102       vpi_printf("ERROR: $split requires 3 arguments, has too many\n");
103       vpi_free_object(arg_iterator);
104       err_flag = 1;
105       break;
106     }
107   } while (0); // end of test group, only executed once
108  
109  
110   if (err_flag)
111     vpi_control(vpiFinish, 1);
112    
113   return (0);
114 }
115 
116 // calltf routine
117 PLI_INT32 split_calltf(PLI_BYTE8* user_data) {
118   vpiHandle systf_handle, arg_iterator, arg_handle;
119   PLI_BYTE8 *svalue;   // string to hold from s_vpi_value
120   PLI_BYTE8 *str;      // string to strtok
121   PLI_BYTE8 *delim;    // delimiter
122   PLI_BYTE8 *tok;      // token for strtok()
123   vpiHandle mem_handle, mem_word_iterator, mem_word_handle;
124   int cnt = 0;
125  
126   s_vpi_value value_s;
127   s_vpi_value memory_word_s;
128  
129   systf_handle = vpi_handle(vpiSysTfCall, NULL);
130   arg_iterator = vpi_iterate(vpiArgument, systf_handle);
131  
132   // read memory from systf arg 1
133   mem_handle = vpi_scan(arg_iterator);
134   // obtain handles to memory word in memory and write current value
135   mem_word_iterator = vpi_iterate(vpiMemoryWord, mem_handle);
136  
137   // read orginal string from systf arg 2
138   arg_handle   = vpi_scan(arg_iterator);
139   value_s.format = vpiStringVal;
140   vpi_get_value(arg_handle, &value_s);
141   svalue = value_s.value.str;
142   str = malloc(strlen((char *)svalue) + 1);
143   strcpy(str, (char *)svalue);
144   ltrim(str, ' ');
145  
146   // read delimiter from systf arg 3
147   arg_handle   = vpi_scan(arg_iterator);
148   vpi_free_object(arg_iterator);
149   value_s.format = vpiStringVal;
150   vpi_get_value(arg_handle, &value_s);
151   svalue = value_s.value.str;
152   delim = malloc(strlen((char *)svalue) + 1);
153   strcpy(delim, (char *)svalue);
154  
155   memory_word_s.format = vpiDecStrVal;
156   tok = strtok(str, delim);
157   while(tok != NULL) {
158     if ((mem_word_handle = vpi_scan(mem_word_iterator)) != NULL) {
159       memory_word_s.value.str = tok;     
160       vpi_put_value(mem_word_handle, &memory_word_s, NULL, vpiNoDelay);
161     }
162      
163     tok = strtok(NULL, delim);
164     cnt++;
165   }
166  
167   // memory is larger than string,
168   // free iterater by hand to prevent from memory leak
169   mem_word_handle = vpi_scan(mem_word_iterator);
170   if (mem_word_handle != NULL)
171     vpi_free_object(mem_word_iterator);
172  
173   // write token count to simulation as return value $split
174   value_s.format = vpiIntVal;
175   value_s.value.integer = cnt;
176   vpi_put_value(systf_handle, &value_s, NULL, vpiNoDelay);
177  
178   free(str);
179   free(delim);
180  
181   return (0);
182 }
183 
184 // register function
185 void split_register() {
186   s_vpi_systf_data tf_data;
187  
188   tf_data.type        = vpiSysFunc;
189   tf_data.sysfunctype = vpiSizedFunc;
190   tf_data.tfname      = "$split";
191   tf_data.calltf      = split_calltf;
192   tf_data.compiletf   = split_compiletf;
193   tf_data.sizetf      = split_sizetf;
194   tf_data.user_data   = NULL;
195   vpi_register_systf(&tf_data);
196 }


15行

// ltrim function
char *ltrim (char *string, char junk) {
 
char* original = string;
 
char *p = original;
 
int trimmed = 0;
 
do {
   
if (*original != junk || trimmed) {
      trimmed
= 1;
     
*p++ = *original;
    }
  }
while (*original++ != '\0');
 
 
return string;
}


的ltrim並非必要,但Verilog的string與C的string有些不同,所以特別補上。在C語言,若string定義比實際string長,char會向左靠攏,並在最後補上\0,但在Verilog卻不是這樣,而是項右靠攏,左側補上空白,所以必須先ltrim清掉左側的空白。

split_tb.v / Verilog

1 /* 
2 (C) OOMusou 2009 http://oomusou.cnblogs.com
3 
4 Filename    : split_tb.v
5 Simulator   : NC-Verilog 5.4
6 Description : testbench for $split()
7 Release     : 05/09/2009 1.0
8 */
9 `timescale 1ns/1ns
10 
11 module split_tb;
12 reg [32*8-1:0] str;
13 reg [1*8-1:0]  delim;
14 reg [31:0] mem [0:2];
15 
16 integer i;
17 integer tok_cnt;
18 
19 initial begin
20 str = "   10,20,30";
21 delim = ",";
22 tok_cnt = $split(mem, str, delim);
23  
24 for(i=0; i<tok_cnt; i=i+1)
25   $display("mem[%1d]=%2d", i, mem[i]);
26  
27 #50;
28 $finish;
29 end
30 endmodule


執行結果

split_v

完整程式碼下載
pli_split.7z

See Also
(筆記) 如何使用C語言實現split()? (C/C++) (C) (JavaScript)

posted on 2009-05-09 23:35  真 OO无双  阅读(3026)  评论(0编辑  收藏  举报

导航