1 |
2 |
sckoarn |
////////////////////////////////////////////////////////////////////////////
|
2 |
|
|
//
|
3 |
|
|
// Copyright 2014 Ken Campbell
|
4 |
|
|
//
|
5 |
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
6 |
|
|
// you may not use this file except in compliance with the License.
|
7 |
|
|
// You may obtain a copy of the License at
|
8 |
|
|
//
|
9 |
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
10 |
|
|
//
|
11 |
|
|
// Unless required by applicable law or agreed to in writing, software
|
12 |
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
13 |
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 |
|
|
// See the License for the specific language governing permissions and
|
15 |
|
|
// limitations under the License.
|
16 |
|
|
//
|
17 |
|
|
/////////////////////////////////////
|
18 |
|
|
// command list class
|
19 |
|
|
class cmd_lst;
|
20 |
|
|
tb_cmd lst_cmds;
|
21 |
|
|
lst_item file_lst;
|
22 |
|
|
lst_item var_lst;
|
23 |
|
|
lst_item inst_lst;
|
24 |
|
|
|
25 |
|
|
integer lst_sz;
|
26 |
|
|
integer lst_idx;
|
27 |
|
|
integer last_idx;
|
28 |
|
|
integer curr_line_num;
|
29 |
|
|
string file_name;
|
30 |
|
|
string include_name;
|
31 |
|
|
|
32 |
|
|
integer call_stack [8:1];
|
33 |
|
|
integer call_index = 0;
|
34 |
|
|
integer loop_cnt [7:0];
|
35 |
|
|
integer loop_term [7:0];
|
36 |
|
|
integer loop_line [7:0];
|
37 |
|
|
integer loop_num = 0;
|
38 |
|
|
integer if_state = 0;
|
39 |
|
|
integer wh_state = 0;
|
40 |
|
|
integer wh_top = 0;
|
41 |
|
|
|
42 |
|
|
//prototypes
|
43 |
|
|
extern function void define_instruction(string inst_txt, int args);
|
44 |
|
|
extern function void define_defaults();
|
45 |
|
|
extern function void load_stm(string stm_file);
|
46 |
|
|
extern function void load_include();
|
47 |
|
|
extern function void add_cmd(tb_cmd cmd);
|
48 |
|
|
extern function void check_cmds();
|
49 |
|
|
extern function tb_trans get(tb_trans inst);
|
50 |
|
|
extern function integer exec_defaults(tb_trans r);
|
51 |
|
|
extern function new();
|
52 |
|
|
extern function void print_cmds();
|
53 |
|
|
extern function void print_str();
|
54 |
|
|
extern function void print_str_wvar();
|
55 |
|
|
endclass // cmd_lst
|
56 |
|
|
|
57 |
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
58 |
|
|
// method definitions.
|
59 |
|
|
///////////////////////////////////////////////////////////
|
60 |
|
|
// function cmd_lst::new
|
61 |
|
|
function cmd_lst::new();
|
62 |
|
|
lst_cmds = new();
|
63 |
|
|
file_lst = new("Files");
|
64 |
|
|
var_lst = new("Variables");
|
65 |
|
|
inst_lst = new("Instructions");
|
66 |
|
|
lst_sz = 0;
|
67 |
|
|
lst_idx = 0;
|
68 |
|
|
last_idx = 0;
|
69 |
|
|
curr_line_num = 0;
|
70 |
|
|
file_name = "";
|
71 |
|
|
include_name = "";
|
72 |
|
|
endfunction // new
|
73 |
|
|
|
74 |
|
|
///////////////////////////////////////////////////////////
|
75 |
|
|
// function cmd_lst::get
|
76 |
|
|
function tb_trans cmd_lst::get(tb_trans inst);
|
77 |
|
|
tb_trans rtn;
|
78 |
|
|
cmd_lst tmp_cmd;
|
79 |
|
|
lst_item tmp_item;
|
80 |
|
|
integer int_val;
|
81 |
|
|
integer tmp_int;
|
82 |
|
|
integer len;
|
83 |
|
|
string tmp_str;
|
84 |
|
|
|
85 |
|
|
rtn = inst;
|
86 |
|
|
rtn.rtn_val.par1 = 0;
|
87 |
|
|
rtn.rtn_val.par2 = 0;
|
88 |
|
|
rtn.rtn_val.par3 = 0;
|
89 |
|
|
rtn.rtn_val.par4 = 0;
|
90 |
|
|
rtn.rtn_val.par5 = 0;
|
91 |
|
|
rtn.rtn_val.par6 = 0;
|
92 |
|
|
|
93 |
|
|
if(rtn.next > rtn.cmd.lst_cmds.idx) begin
|
94 |
|
|
while (rtn.next > rtn.cmd.lst_cmds.idx && rtn.cmd.lst_cmds != null) begin
|
95 |
|
|
rtn.cmd.lst_cmds = rtn.cmd.lst_cmds.next;
|
96 |
|
|
check_get_next : assert (rtn.cmd.lst_cmds != null) else begin
|
97 |
|
|
$fatal(0, "cmd_lst::get failed due to attemped access to commands behond the end of the script.");
|
98 |
|
|
end
|
99 |
|
|
end
|
100 |
|
|
end else if (rtn.next < rtn.cmd.lst_cmds.idx) begin
|
101 |
|
|
while (rtn.next < rtn.cmd.lst_cmds.idx && rtn.cmd.lst_cmds != null) begin
|
102 |
|
|
rtn.cmd.lst_cmds = rtn.cmd.lst_cmds.prev;
|
103 |
|
|
check_get_prev : assert (rtn.cmd.lst_cmds != null) else begin
|
104 |
|
|
$fatal(0, "cmd_lst::get failed due to attemped access to commands before the beginning of the script.");
|
105 |
|
|
end
|
106 |
|
|
end
|
107 |
|
|
end
|
108 |
|
|
|
109 |
|
|
rtn.rtn_val.cmd = rtn.cmd.lst_cmds.cmd;
|
110 |
|
|
for (int i = 1; i <= rtn.cmd.lst_cmds.valid_fld - 1; i++) begin
|
111 |
|
|
case (i)
|
112 |
|
|
1: tmp_str = rtn.cmd.lst_cmds.var1;
|
113 |
|
|
2: tmp_str = rtn.cmd.lst_cmds.var2;
|
114 |
|
|
3: tmp_str = rtn.cmd.lst_cmds.var3;
|
115 |
|
|
4: tmp_str = rtn.cmd.lst_cmds.var4;
|
116 |
|
|
5: tmp_str = rtn.cmd.lst_cmds.var5;
|
117 |
|
|
6: tmp_str = rtn.cmd.lst_cmds.var6;
|
118 |
|
|
default: $display("ERROR: more than six parameters ????");
|
119 |
|
|
endcase
|
120 |
|
|
tmp_int = is_var(tmp_str);
|
121 |
|
|
if (tmp_int == 0) begin
|
122 |
|
|
tmp_int = stm2_int(tmp_str);
|
123 |
|
|
end else if (tmp_int == 1) begin
|
124 |
|
|
len = tmp_str.len();
|
125 |
|
|
tmp_str = tmp_str.substr(1, len - 1);
|
126 |
|
|
tmp_item = rtn.cmd.var_lst.find(tmp_str);
|
127 |
|
|
tmp_int = tmp_item.val;
|
128 |
|
|
end else if (tmp_int == 2) begin
|
129 |
|
|
tmp_item = rtn.cmd.var_lst.find(tmp_str);
|
130 |
|
|
tmp_int = tmp_item.index;
|
131 |
|
|
end else if (tmp_int == 3) begin
|
132 |
|
|
case (tmp_str)
|
133 |
|
|
"==" : tmp_int = 0;
|
134 |
|
|
"!=" : tmp_int = 1;
|
135 |
|
|
">" : tmp_int = 2;
|
136 |
|
|
"<" : tmp_int = 3;
|
137 |
|
|
">=" : tmp_int = 4;
|
138 |
|
|
"<=" : tmp_int = 5;
|
139 |
|
|
default : $display("Condition text not found ???");
|
140 |
|
|
endcase
|
141 |
|
|
end else begin
|
142 |
|
|
$display("is_var() returned an unknown value???");
|
143 |
|
|
end
|
144 |
|
|
|
145 |
|
|
case (i)
|
146 |
|
|
1: rtn.rtn_val.par1 = tmp_int;
|
147 |
|
|
2: rtn.rtn_val.par2 = tmp_int;
|
148 |
|
|
3: rtn.rtn_val.par3 = tmp_int;
|
149 |
|
|
4: rtn.rtn_val.par4 = tmp_int;
|
150 |
|
|
5: rtn.rtn_val.par5 = tmp_int;
|
151 |
|
|
6: rtn.rtn_val.par6 = tmp_int;
|
152 |
|
|
default: $display("ERROR: more than six parameters ????");
|
153 |
|
|
endcase
|
154 |
|
|
end
|
155 |
|
|
|
156 |
|
|
return rtn;
|
157 |
|
|
endfunction
|
158 |
|
|
|
159 |
|
|
///////////////////////////////////////////////////////////
|
160 |
|
|
// function cmd_lst::define_instruction
|
161 |
|
|
function void cmd_lst::define_instruction(string inst_txt, int args);
|
162 |
|
|
lst_item tmp_lst;
|
163 |
|
|
lst_item new_itm;
|
164 |
|
|
integer stat = 0;
|
165 |
|
|
// search the list for this instruction
|
166 |
|
|
tmp_lst = new("");
|
167 |
|
|
tmp_lst = this.inst_lst;
|
168 |
|
|
while(tmp_lst != null) begin
|
169 |
|
|
if(tmp_lst.txt != inst_txt) begin
|
170 |
|
|
tmp_lst = tmp_lst.next;
|
171 |
|
|
end else begin
|
172 |
|
|
check_duplicate_inst : assert (0) else begin
|
173 |
|
|
$fatal(0, "Duplicate instruction definition attempted : %s", inst_txt);
|
174 |
|
|
end
|
175 |
|
|
//$display("ERROR: Duplicate instruction definition attempted : %s", inst_txt);
|
176 |
|
|
//stat = 1;
|
177 |
|
|
//return stat;
|
178 |
|
|
end
|
179 |
|
|
end
|
180 |
|
|
// all good lets add this instruction to the list
|
181 |
|
|
new_itm = new("");
|
182 |
|
|
new_itm.txt = inst_txt;
|
183 |
|
|
new_itm.val = args;
|
184 |
|
|
inst_lst.add_itm(new_itm);
|
185 |
|
|
|
186 |
|
|
//return stat;
|
187 |
|
|
endfunction // define_instruction
|
188 |
|
|
|
189 |
|
|
/////////////////////////////////////////////////////////
|
190 |
|
|
// function cmd_lst::add_cmd
|
191 |
|
|
// INPUT: tb_cmd cmd
|
192 |
|
|
function void cmd_lst::add_cmd(tb_cmd cmd);
|
193 |
|
|
tb_cmd tmp_cmd;
|
194 |
|
|
tb_cmd new_cmd;
|
195 |
|
|
integer stat = 0;
|
196 |
|
|
|
197 |
|
|
tmp_cmd = new();
|
198 |
|
|
tmp_cmd = this.lst_cmds;
|
199 |
|
|
|
200 |
|
|
// first
|
201 |
|
|
if((this.lst_cmds.next == null) && (this.lst_cmds.cmd == "")) begin
|
202 |
|
|
new_cmd = new();
|
203 |
|
|
new_cmd = cmd;
|
204 |
|
|
new_cmd.idx = 0;
|
205 |
|
|
this.lst_cmds = new_cmd;
|
206 |
|
|
// second
|
207 |
|
|
end else if(this.lst_cmds.next == null) begin
|
208 |
|
|
new_cmd = new();
|
209 |
|
|
new_cmd = cmd;
|
210 |
|
|
new_cmd.idx = 1;
|
211 |
|
|
tmp_cmd.next = new_cmd;
|
212 |
|
|
new_cmd.prev = tmp_cmd;
|
213 |
|
|
// rest
|
214 |
|
|
end else begin
|
215 |
|
|
while (tmp_cmd.next != null) begin
|
216 |
|
|
tmp_cmd = tmp_cmd.next;
|
217 |
|
|
end
|
218 |
|
|
new_cmd = new();
|
219 |
|
|
new_cmd = cmd;
|
220 |
|
|
new_cmd.idx = tmp_cmd.idx + 1;
|
221 |
|
|
tmp_cmd.next = new_cmd;
|
222 |
|
|
new_cmd.prev = tmp_cmd;
|
223 |
|
|
end
|
224 |
|
|
this.lst_sz++;
|
225 |
|
|
this.last_idx = new_cmd.idx;
|
226 |
|
|
endfunction
|
227 |
|
|
|
228 |
|
|
/////////////////////////////////////////////////////////
|
229 |
|
|
// function cmd_lst::load stimulus
|
230 |
|
|
function void cmd_lst::load_stm(string stm_file);
|
231 |
|
|
tb_cmd new_cmd;
|
232 |
|
|
tb_cmd tst_cmd;
|
233 |
|
|
integer in_fh;
|
234 |
|
|
integer stat = 0;
|
235 |
|
|
integer fstat = 0;
|
236 |
|
|
integer idx = 0;
|
237 |
|
|
integer len;
|
238 |
|
|
integer i, ilen;
|
239 |
|
|
string input_str;
|
240 |
|
|
string tstr;
|
241 |
|
|
lst_item tmp_item;
|
242 |
|
|
// open the file passed and test for existance.
|
243 |
|
|
in_fh = $fopen(stm_file, "r");
|
244 |
|
|
check_file_open : assert (in_fh != 0) else begin
|
245 |
|
|
$fatal(0, "ERROR: File not found in cmd_lst::load_stm : %s", stm_file);
|
246 |
|
|
end
|
247 |
|
|
|
248 |
|
|
this.file_name = stm_file;
|
249 |
|
|
// this is the main file, add to file list.
|
250 |
|
|
tmp_item = new("");
|
251 |
|
|
tmp_item.txt = stm_file;
|
252 |
|
|
file_lst.add_itm(tmp_item);
|
253 |
|
|
|
254 |
|
|
this.curr_line_num = 0;
|
255 |
|
|
// new the test results storage ...
|
256 |
|
|
tmp_item = new("");
|
257 |
|
|
|
258 |
|
|
while (! $feof(in_fh)) begin
|
259 |
|
|
fstat = $fgets(input_str, in_fh);
|
260 |
|
|
// increment the line number
|
261 |
|
|
this.curr_line_num++;
|
262 |
|
|
tst_cmd = new();
|
263 |
|
|
if (input_str == "\n" || input_str == "")
|
264 |
|
|
continue;
|
265 |
|
|
// check for special commands DEFINE_VAR and INCLUDE
|
266 |
|
|
tst_cmd = tst_cmd.parse_cmd(input_str);
|
267 |
|
|
len = tst_cmd.cmd.len();
|
268 |
|
|
if (tst_cmd.cmd == "DEFINE_VAR") begin
|
269 |
|
|
tmp_item.txt = tst_cmd.var1;
|
270 |
|
|
tmp_item.val = stm2_int(tst_cmd.var2);
|
271 |
|
|
var_lst.add_itm(tmp_item);
|
272 |
|
|
// check for INCLUDE file def
|
273 |
|
|
end else if (tst_cmd.cmd == "INCLUDE") begin
|
274 |
|
|
if(tst_cmd.var1 != "") begin
|
275 |
|
|
this.include_name = tst_cmd.var1;
|
276 |
|
|
end else if (tst_cmd.cmd_str != "") begin
|
277 |
|
|
tstr = tst_cmd.cmd_str;
|
278 |
|
|
ilen = tstr.len();
|
279 |
|
|
i = ilen-1;
|
280 |
|
|
// strip any trailing spaces
|
281 |
|
|
while(tstr[i] == " ") begin
|
282 |
|
|
tstr = tstr.substr(0,i-1);
|
283 |
|
|
i--;
|
284 |
|
|
end
|
285 |
|
|
this.include_name = tstr;
|
286 |
|
|
end else begin
|
287 |
|
|
check_include : assert (0) else begin
|
288 |
|
|
$fatal(0, "No INCLUDE file found in command on\n line: %4d in file: %s", curr_line_num, stm_file);
|
289 |
|
|
end
|
290 |
|
|
end
|
291 |
|
|
this.load_include();
|
292 |
|
|
// check for inline variable.
|
293 |
|
|
end else if(tst_cmd.cmd[len-1] == ":") begin
|
294 |
|
|
tmp_item.txt = tst_cmd.cmd.substr(0, len-2);
|
295 |
|
|
tmp_item.val = this.last_idx + 1;
|
296 |
|
|
var_lst.add_itm(tmp_item);
|
297 |
|
|
// else is a standard command
|
298 |
|
|
end else begin
|
299 |
|
|
// parse out the command
|
300 |
|
|
new_cmd = new();
|
301 |
|
|
new_cmd = new_cmd.parse_cmd(input_str);
|
302 |
|
|
if (new_cmd.valid_fld > 0) begin
|
303 |
|
|
new_cmd.line_num = curr_line_num;
|
304 |
|
|
new_cmd.file_idx = 0;
|
305 |
|
|
this.add_cmd(new_cmd);
|
306 |
|
|
end
|
307 |
|
|
end
|
308 |
|
|
end // while (! $feof(in_fh))
|
309 |
|
|
|
310 |
|
|
check_cmds();
|
311 |
|
|
endfunction // load_stm
|
312 |
|
|
//////////////////////////////////////////////////////
|
313 |
|
|
// function cmd_lst::load_include
|
314 |
|
|
function void cmd_lst::load_include();
|
315 |
|
|
tb_cmd tmp_cmd;
|
316 |
|
|
tb_cmd new_cmd;
|
317 |
|
|
tb_cmd tst_cmd;
|
318 |
|
|
integer inc_fh;
|
319 |
|
|
integer stat = 0;
|
320 |
|
|
integer idx = 0;
|
321 |
|
|
string input_str;
|
322 |
|
|
lst_item tmp_item;
|
323 |
|
|
lst_item var_item;
|
324 |
|
|
integer file_idx;
|
325 |
|
|
integer len;
|
326 |
|
|
integer file_line = 0;
|
327 |
|
|
|
328 |
|
|
// open the file passed and test for existance.
|
329 |
|
|
inc_fh = $fopen(this.include_name, "r");
|
330 |
|
|
check_include_open : assert(inc_fh != 0) else begin
|
331 |
|
|
$fatal(0, "INCLUDE File not found: %s\nFound in file: %s\nOn line: %4d", this.include_name, this.file_name, this.curr_line_num);
|
332 |
|
|
end
|
333 |
|
|
|
334 |
|
|
// this is an include file, add to list.
|
335 |
|
|
tmp_item = new("");
|
336 |
|
|
tmp_item.txt = this.include_name;
|
337 |
|
|
file_lst.add_itm(tmp_item);
|
338 |
|
|
tmp_item = file_lst.find(this.include_name);
|
339 |
|
|
file_idx = tmp_item.index;
|
340 |
|
|
|
341 |
|
|
// new the test results storage ...
|
342 |
|
|
var_item = new("");
|
343 |
|
|
|
344 |
|
|
while (! $feof(inc_fh)) begin
|
345 |
|
|
file_line++;
|
346 |
|
|
stat = $fgets(input_str, inc_fh);
|
347 |
|
|
tst_cmd = new();
|
348 |
|
|
// skip blank lines
|
349 |
|
|
if (input_str == "\n" || input_str == "")
|
350 |
|
|
continue;
|
351 |
|
|
// check for special commands DEFINE_VAR, INCLUDE and inline variables
|
352 |
|
|
tst_cmd = tst_cmd.parse_cmd(input_str);
|
353 |
|
|
len = tst_cmd.cmd.len();
|
354 |
|
|
// DEFINE_VAR
|
355 |
|
|
if (tst_cmd.cmd == "DEFINE_VAR") begin
|
356 |
|
|
var_item.txt = tst_cmd.var1;
|
357 |
|
|
var_item.val = stm2_int(tst_cmd.var2);
|
358 |
|
|
var_lst.add_itm(var_item);
|
359 |
|
|
continue;
|
360 |
|
|
// INCLUDE Not nested.
|
361 |
|
|
end else if (tst_cmd.cmd == "INCLUDE") begin
|
362 |
|
|
check_nest_include : assert (0) else begin
|
363 |
|
|
$fatal(0, "INCLUDE can not be nested!!\nFound in file: %s\nOn line: %4d", this.include_name, file_line);
|
364 |
|
|
end
|
365 |
|
|
// In line VAR
|
366 |
|
|
end else if (tst_cmd.cmd[len - 1] == ":") begin
|
367 |
|
|
var_item.txt = tst_cmd.cmd.substr(0, len-2);
|
368 |
|
|
var_item.val = this.last_idx + 1;
|
369 |
|
|
var_lst.add_itm(var_item);
|
370 |
|
|
continue;
|
371 |
|
|
end
|
372 |
|
|
// parse out the command
|
373 |
|
|
new_cmd = new();
|
374 |
|
|
new_cmd = new_cmd.parse_cmd(input_str);
|
375 |
|
|
if (new_cmd.valid_fld > 0) begin
|
376 |
|
|
new_cmd.file_idx = file_idx;
|
377 |
|
|
new_cmd.line_num = file_line;
|
378 |
|
|
this.add_cmd(new_cmd);
|
379 |
|
|
end
|
380 |
|
|
end // while (! $feof(inc_fh))
|
381 |
|
|
endfunction // load_include
|
382 |
|
|
|
383 |
|
|
////////////////////////////////////////////////////////////
|
384 |
|
|
// function check_cmds
|
385 |
|
|
// checks that the commands loaded exist, have correct # params and
|
386 |
|
|
// variable names exist
|
387 |
|
|
function void cmd_lst::check_cmds();
|
388 |
|
|
tb_cmd tmp_cmd;
|
389 |
|
|
tb_cmd dum;
|
390 |
|
|
int found;
|
391 |
|
|
string cname;
|
392 |
|
|
string fname;
|
393 |
|
|
string t_var;
|
394 |
|
|
byte c;
|
395 |
|
|
int num_params;
|
396 |
|
|
lst_item tmp_lst;
|
397 |
|
|
lst_item flst;
|
398 |
|
|
lst_item tmp_item;
|
399 |
|
|
integer stat = 0;
|
400 |
|
|
integer file_idx;
|
401 |
|
|
integer len;
|
402 |
|
|
integer vtype;
|
403 |
|
|
|
404 |
|
|
tmp_cmd = this.lst_cmds;
|
405 |
|
|
// go through all the commands from the stimulus file.
|
406 |
|
|
while(tmp_cmd != null) begin
|
407 |
|
|
cname = tmp_cmd.cmd;
|
408 |
|
|
num_params = tmp_cmd.valid_fld;
|
409 |
|
|
tmp_lst = this.inst_lst;
|
410 |
|
|
found = 0;
|
411 |
|
|
// get the file name from this command
|
412 |
|
|
file_idx = tmp_cmd.file_idx;
|
413 |
|
|
flst = this.file_lst;
|
414 |
|
|
while (flst != null) begin
|
415 |
|
|
if(flst.index == file_idx) begin
|
416 |
|
|
fname = flst.txt;
|
417 |
|
|
end
|
418 |
|
|
flst = flst.next;
|
419 |
|
|
end
|
420 |
|
|
// go through the list of valid commands
|
421 |
|
|
while (tmp_lst != null && found == 0) begin
|
422 |
|
|
if (tmp_lst.txt == cname) begin
|
423 |
|
|
found = 1;
|
424 |
|
|
check_num_params : assert ((tmp_lst.val == num_params - 1) || (tmp_lst.val >= 7)) else begin
|
425 |
|
|
$fatal(0, "Incorrect number of parameters found in command on\n line: %4d in file: %s", tmp_cmd.line_num, fname);
|
426 |
|
|
end
|
427 |
|
|
end
|
428 |
|
|
tmp_lst = tmp_lst.next;
|
429 |
|
|
end
|
430 |
|
|
// if we did not find a command
|
431 |
|
|
check_valid_instruction : assert (found != 0) else begin
|
432 |
|
|
$fatal(0, "Command %s was not found in the list of valid commands on\n line: %4d in file: %s", cname, tmp_cmd.line_num, fname);
|
433 |
|
|
end
|
434 |
|
|
|
435 |
|
|
// Check the line for invalid variable names
|
436 |
|
|
if(num_params != 0) begin
|
437 |
|
|
tmp_lst = this.var_lst;
|
438 |
|
|
for (int i = 1; i <= num_params - 1; i++) begin
|
439 |
|
|
case (i)
|
440 |
|
|
1: t_var = tmp_cmd.var1;
|
441 |
|
|
2: t_var = tmp_cmd.var2;
|
442 |
|
|
3: t_var = tmp_cmd.var3;
|
443 |
|
|
4: t_var = tmp_cmd.var4;
|
444 |
|
|
5: t_var = tmp_cmd.var5;
|
445 |
|
|
6: t_var = tmp_cmd.var6;
|
446 |
|
|
default: $display("ERROR: num_params greater than six???");
|
447 |
|
|
endcase
|
448 |
|
|
c = t_var[0];
|
449 |
|
|
vtype = is_var(t_var);
|
450 |
|
|
if(vtype) begin
|
451 |
|
|
if(c == "$") begin
|
452 |
|
|
len = t_var.len();
|
453 |
|
|
t_var = t_var.substr(1, len - 1);
|
454 |
|
|
end
|
455 |
|
|
// if condition operator skip
|
456 |
|
|
if(vtype == 3) begin
|
457 |
|
|
continue;
|
458 |
|
|
end
|
459 |
|
|
end else begin
|
460 |
|
|
continue;
|
461 |
|
|
end
|
462 |
|
|
tmp_item = var_lst.find(t_var);
|
463 |
|
|
check_valid_variable : assert (tmp_item != null) else begin
|
464 |
|
|
$fatal(0, "Variable number: %2d >>> %s <<< on line %4d in file: %s Is NOT defined!!", i, t_var, tmp_cmd.line_num, fname);
|
465 |
|
|
end
|
466 |
|
|
end
|
467 |
|
|
end
|
468 |
|
|
|
469 |
|
|
tmp_cmd = tmp_cmd.next;
|
470 |
|
|
end
|
471 |
|
|
endfunction // cmd_lst::check_cmds
|
472 |
|
|
|
473 |
|
|
/////////////////////////////////////////////////////////////
|
474 |
|
|
//
|
475 |
|
|
function void cmd_lst::define_defaults();
|
476 |
|
|
this.define_instruction("ABORT", 0);
|
477 |
|
|
this.define_instruction("FINISH", 0);
|
478 |
|
|
this.define_instruction("EQU_VAR", 2);
|
479 |
|
|
this.define_instruction("ADD_VAR", 2);
|
480 |
|
|
this.define_instruction("SUB_VAR", 2);
|
481 |
|
|
this.define_instruction("CALL", 1);
|
482 |
|
|
this.define_instruction("RETURN_CALL", 0);
|
483 |
|
|
this.define_instruction("JUMP", 1);
|
484 |
|
|
this.define_instruction("LOOP", 1);
|
485 |
|
|
this.define_instruction("END_LOOP", 0);
|
486 |
|
|
this.define_instruction("IF", 3);
|
487 |
|
|
this.define_instruction("ELSEIF", 3);
|
488 |
|
|
this.define_instruction("ELSE", 0);
|
489 |
|
|
this.define_instruction("END_IF", 0);
|
490 |
|
|
this.define_instruction("WHILE", 3);
|
491 |
|
|
this.define_instruction("END_WHILE", 0);
|
492 |
|
|
endfunction // define_defaults
|
493 |
|
|
|
494 |
|
|
///////////////////////////////////////////////////////////////////
|
495 |
|
|
//
|
496 |
|
|
function integer cmd_lst::exec_defaults(tb_trans r);
|
497 |
|
|
integer rtn = 0;
|
498 |
|
|
lst_item tmp_item;
|
499 |
|
|
integer idx = 0;
|
500 |
|
|
string cmd_string;
|
501 |
|
|
|
502 |
|
|
// get the command string
|
503 |
|
|
cmd_string = r.cmd.lst_cmds.cmd;
|
504 |
|
|
// output the dynamic text if there is some. (Note: before command runs.)
|
505 |
|
|
r.cmd.print_str_wvar();
|
506 |
|
|
|
507 |
|
|
/// The Main else if chain /////////////////////////////////////////////////
|
508 |
|
|
// ABORT
|
509 |
|
|
if(cmd_string == "ABORT") begin
|
510 |
|
|
$display("The test has aborted due to an error!!");
|
511 |
|
|
$finish(2);
|
512 |
|
|
rtn = 1;
|
513 |
|
|
///////////////////////////////////////////////////////////////////////////
|
514 |
|
|
// FINISH
|
515 |
|
|
end else if (cmd_string == "FINISH") begin
|
516 |
|
|
$display("Test Finished with NO error!!");
|
517 |
|
|
$finish();
|
518 |
|
|
rtn = 1;
|
519 |
|
|
///////////////////////////////////////////////////////////////////////////
|
520 |
|
|
// ADD_VAR
|
521 |
|
|
end else if (cmd_string == "ADD_VAR") begin
|
522 |
|
|
tmp_item = this.var_lst.get(r.rtn_val.par1);
|
523 |
|
|
idx = tmp_item.index;
|
524 |
|
|
tmp_item.val = tmp_item.val + r.rtn_val.par2;
|
525 |
|
|
r.cmd.var_lst.set(idx, tmp_item.val);
|
526 |
|
|
rtn = 1;
|
527 |
|
|
///////////////////////////////////////////////////////////////////////////
|
528 |
|
|
// SUB_VAR
|
529 |
|
|
end else if (cmd_string == "SUB_VAR") begin
|
530 |
|
|
tmp_item = this.var_lst.get(r.rtn_val.par1);
|
531 |
|
|
idx = tmp_item.index;
|
532 |
|
|
tmp_item.val = tmp_item.val - r.rtn_val.par2;
|
533 |
|
|
r.cmd.var_lst.set(idx, tmp_item.val);
|
534 |
|
|
rtn = 1;
|
535 |
|
|
///////////////////////////////////////////////////////////////////////////
|
536 |
|
|
// EQU_VAR
|
537 |
|
|
end else if (cmd_string == "EQU_VAR") begin
|
538 |
|
|
tmp_item = this.var_lst.get(r.rtn_val.par1);
|
539 |
|
|
idx = tmp_item.index;
|
540 |
|
|
tmp_item.val = r.rtn_val.par2;
|
541 |
|
|
r.cmd.var_lst.set(idx, tmp_item.val);
|
542 |
|
|
rtn = 1;
|
543 |
|
|
///////////////////////////////////////////////////////////////////////////
|
544 |
|
|
// CALL
|
545 |
|
|
end else if (cmd_string == "CALL") begin
|
546 |
|
|
call_index++;
|
547 |
|
|
check_call_depth : assert(call_index <= 8) else begin
|
548 |
|
|
$fatal(0,"CALL nesting depth maximum is 7. On Line: %4d", r.cmd.lst_cmds.line_num);
|
549 |
|
|
end
|
550 |
|
|
call_stack[call_index] = r.cmd.lst_cmds.idx + 1;
|
551 |
|
|
r.next = r.rtn_val.par1;
|
552 |
|
|
rtn = 1;
|
553 |
|
|
///////////////////////////////////////////////////////////////////////////
|
554 |
|
|
// RETURN_CALL
|
555 |
|
|
end else if (cmd_string == "RETURN_CALL") begin
|
556 |
|
|
check_call_under_run : assert(call_index > 0) else begin
|
557 |
|
|
$fatal(0,"RETURN_CALL causing nesting underflow?. On Line: %4d", r.cmd.lst_cmds.line_num);
|
558 |
|
|
end
|
559 |
|
|
r.next = call_stack[call_index];
|
560 |
|
|
call_index--;
|
561 |
|
|
rtn = 1;
|
562 |
|
|
///////////////////////////////////////////////////////////////////////////
|
563 |
|
|
// JUMP
|
564 |
|
|
end else if (cmd_string == "JUMP") begin
|
565 |
|
|
r.next = r.rtn_val.par1;
|
566 |
|
|
call_index = 0;
|
567 |
|
|
rtn = 1;
|
568 |
|
|
///////////////////////////////////////////////////////////////////////////
|
569 |
|
|
// LOOP
|
570 |
|
|
end else if (cmd_string == "LOOP") begin
|
571 |
|
|
loop_num++;
|
572 |
|
|
loop_line[loop_num] = r.cmd.lst_cmds.idx + 1;
|
573 |
|
|
loop_cnt[loop_num] = 0;
|
574 |
|
|
loop_term[loop_num] = r.rtn_val.par1;
|
575 |
|
|
rtn = 1;
|
576 |
|
|
///////////////////////////////////////////////////////////////////////////
|
577 |
|
|
// END_LOOP
|
578 |
|
|
end else if (cmd_string == "END_LOOP") begin
|
579 |
|
|
loop_cnt[loop_num]++;
|
580 |
|
|
if(loop_cnt[loop_num] == loop_term[loop_num]) begin
|
581 |
|
|
loop_num--;
|
582 |
|
|
r.next = r.cmd.lst_cmds.idx + 1;
|
583 |
|
|
end else begin
|
584 |
|
|
r.next = loop_line[loop_num];
|
585 |
|
|
end
|
586 |
|
|
rtn = 1;
|
587 |
|
|
///////////////////////////////////////////////////////////////////////////
|
588 |
|
|
// IF
|
589 |
|
|
end else if (cmd_string == "IF") begin
|
590 |
|
|
if_state = 0;
|
591 |
|
|
case (r.rtn_val.par2)
|
592 |
|
|
0: if(r.rtn_val.par1 == r.rtn_val.par3) if_state = 1;
|
593 |
|
|
1: if(r.rtn_val.par1 != r.rtn_val.par3) if_state = 1;
|
594 |
|
|
2: if(r.rtn_val.par1 > r.rtn_val.par3) if_state = 1;
|
595 |
|
|
3: if(r.rtn_val.par1 < r.rtn_val.par3) if_state = 1;
|
596 |
|
|
4: if(r.rtn_val.par1 >= r.rtn_val.par3) if_state = 1;
|
597 |
|
|
5: if(r.rtn_val.par1 <= r.rtn_val.par3) if_state = 1;
|
598 |
|
|
default: if_op_error : assert (0) else begin
|
599 |
|
|
$fatal(0, "IF statement had unknown operator in par2. On Line: %4d", r.cmd.lst_cmds.line_num);
|
600 |
|
|
end
|
601 |
|
|
endcase
|
602 |
|
|
|
603 |
|
|
if (!if_state) begin
|
604 |
|
|
r = r.cmd.get(r);
|
605 |
|
|
cmd_string = r.cmd.lst_cmds.cmd;
|
606 |
|
|
r.next++;
|
607 |
|
|
while(cmd_string != "ELSE" && cmd_string != "ELSEIF" && cmd_string != "END_IF") begin
|
608 |
|
|
r = r.cmd.get(r);
|
609 |
|
|
cmd_string = r.cmd.lst_cmds.cmd;
|
610 |
|
|
r.next++;
|
611 |
|
|
check_if_end : assert (r.cmd.lst_cmds.next != null) else begin
|
612 |
|
|
$fatal(0,"Unable to find terminating element for IF statement!!");
|
613 |
|
|
end
|
614 |
|
|
end
|
615 |
|
|
r.next--;
|
616 |
|
|
end
|
617 |
|
|
rtn = 1;
|
618 |
|
|
///////////////////////////////////////////////////////////////////////////
|
619 |
|
|
// ELSEIF
|
620 |
|
|
end else if (cmd_string == "ELSEIF") begin
|
621 |
|
|
if(if_state) begin
|
622 |
|
|
r = r.cmd.get(r);
|
623 |
|
|
cmd_string = r.cmd.lst_cmds.cmd;
|
624 |
|
|
r.next++;
|
625 |
|
|
while(cmd_string != "END_IF") begin
|
626 |
|
|
r = r.cmd.get(r);
|
627 |
|
|
cmd_string = r.cmd.lst_cmds.cmd;
|
628 |
|
|
r.next++;
|
629 |
|
|
check_elseif_statement : assert (r.cmd.lst_cmds.next != null) else begin
|
630 |
|
|
$fatal(0,"Unable to find terminating element for ESLEIF statement!!");
|
631 |
|
|
end
|
632 |
|
|
end
|
633 |
|
|
r.next--;
|
634 |
|
|
end else begin
|
635 |
|
|
case (r.rtn_val.par2)
|
636 |
|
|
0: if(r.rtn_val.par1 == r.rtn_val.par3) if_state = 1;
|
637 |
|
|
1: if(r.rtn_val.par1 != r.rtn_val.par3) if_state = 1;
|
638 |
|
|
2: if(r.rtn_val.par1 > r.rtn_val.par3) if_state = 1;
|
639 |
|
|
3: if(r.rtn_val.par1 < r.rtn_val.par3) if_state = 1;
|
640 |
|
|
4: if(r.rtn_val.par1 >= r.rtn_val.par3) if_state = 1;
|
641 |
|
|
5: if(r.rtn_val.par1 <= r.rtn_val.par3) if_state = 1;
|
642 |
|
|
default: elseif_op_error : assert (0) else begin
|
643 |
|
|
$fatal(0, "ELSEIF statement had unknown operator in par2. On Line: %4d", r.cmd.lst_cmds.line_num);
|
644 |
|
|
end
|
645 |
|
|
endcase
|
646 |
|
|
|
647 |
|
|
if (!if_state) begin
|
648 |
|
|
r = r.cmd.get(r);
|
649 |
|
|
cmd_string = r.cmd.lst_cmds.cmd;
|
650 |
|
|
r.next++;
|
651 |
|
|
while(cmd_string != "ELSE" && cmd_string != "ELSEIF" && cmd_string != "END_IF") begin
|
652 |
|
|
r = r.cmd.get(r);
|
653 |
|
|
cmd_string = r.cmd.lst_cmds.cmd;
|
654 |
|
|
r.next++;
|
655 |
|
|
check_elseif_end : assert (r.cmd.lst_cmds.next != null) else begin
|
656 |
|
|
$fatal(0,"Unable to find terminating element for IF statement!!");
|
657 |
|
|
end
|
658 |
|
|
end
|
659 |
|
|
r.next--;
|
660 |
|
|
end
|
661 |
|
|
end
|
662 |
|
|
rtn = 1;
|
663 |
|
|
///////////////////////////////////////////////////////////////////////////
|
664 |
|
|
// ELSEIF
|
665 |
|
|
end else if (cmd_string == "ELSE") begin
|
666 |
|
|
if(if_state) begin
|
667 |
|
|
r = r.cmd.get(r);
|
668 |
|
|
cmd_string = r.cmd.lst_cmds.cmd;
|
669 |
|
|
r.next++;
|
670 |
|
|
while(cmd_string != "END_IF") begin
|
671 |
|
|
r = r.cmd.get(r);
|
672 |
|
|
cmd_string = r.cmd.lst_cmds.cmd;
|
673 |
|
|
r.next++;
|
674 |
|
|
check_else_statement : assert (r.cmd.lst_cmds.next != null) else begin
|
675 |
|
|
$fatal(0,"Unable to find terminating element for ELSE statement!!");
|
676 |
|
|
end
|
677 |
|
|
end
|
678 |
|
|
r.next--;
|
679 |
|
|
end
|
680 |
|
|
rtn = 1;
|
681 |
|
|
///////////////////////////////////////////////////////////////////////////
|
682 |
|
|
// END_IF
|
683 |
|
|
end else if (cmd_string == "END_IF") begin
|
684 |
|
|
rtn = 1;
|
685 |
|
|
// This command is just a place holder, skip to next instruction.
|
686 |
|
|
|
687 |
|
|
///////////////////////////////////////////////////////////////////////////
|
688 |
|
|
// WHILE non-nested implementation
|
689 |
|
|
end else if (cmd_string == "WHILE") begin
|
690 |
|
|
wh_state = 0;
|
691 |
|
|
wh_top = r.cmd.lst_cmds.idx;
|
692 |
|
|
case (r.rtn_val.par2)
|
693 |
|
|
0: if(r.rtn_val.par1 == r.rtn_val.par3) wh_state = 1;
|
694 |
|
|
1: if(r.rtn_val.par1 != r.rtn_val.par3) wh_state = 1;
|
695 |
|
|
2: if(r.rtn_val.par1 > r.rtn_val.par3) wh_state = 1;
|
696 |
|
|
3: if(r.rtn_val.par1 < r.rtn_val.par3) wh_state = 1;
|
697 |
|
|
4: if(r.rtn_val.par1 >= r.rtn_val.par3) wh_state = 1;
|
698 |
|
|
5: if(r.rtn_val.par1 <= r.rtn_val.par3) wh_state = 1;
|
699 |
|
|
default: while_op_error : assert (0) else begin
|
700 |
|
|
$fatal(0, "WHILE statement had unknown operator in par2. On Line: %4d", r.cmd.lst_cmds.line_num);
|
701 |
|
|
end
|
702 |
|
|
endcase
|
703 |
|
|
|
704 |
|
|
if(!wh_state) begin
|
705 |
|
|
while(cmd_string != "END_WHILE") begin
|
706 |
|
|
r = r.cmd.get(r);
|
707 |
|
|
cmd_string = r.cmd.lst_cmds.cmd;
|
708 |
|
|
r.next++;
|
709 |
|
|
check_while_statement : assert (r.cmd.lst_cmds.next != null) else begin
|
710 |
|
|
$fatal(0,"Unable to find terminating element for WHILE statement!!");
|
711 |
|
|
end
|
712 |
|
|
end
|
713 |
|
|
end
|
714 |
|
|
rtn = 1;
|
715 |
|
|
|
716 |
|
|
///////////////////////////////////////////////////////////////////////////
|
717 |
|
|
// END_WHILE
|
718 |
|
|
end else if (cmd_string == "END_WHILE") begin
|
719 |
|
|
r.next = wh_top;
|
720 |
|
|
rtn = 1;
|
721 |
|
|
end
|
722 |
|
|
|
723 |
|
|
return rtn;
|
724 |
|
|
endfunction // exec_defaults
|
725 |
|
|
|
726 |
|
|
// dynamic print function.
|
727 |
|
|
function void cmd_lst::print_str();
|
728 |
|
|
if (this.lst_cmds.cmd_str != "") begin
|
729 |
|
|
$display("%s", this.lst_cmds.cmd_str);
|
730 |
|
|
end
|
731 |
|
|
endfunction
|
732 |
|
|
|
733 |
|
|
// dynamic print function with variable sub
|
734 |
|
|
// output var in HEX.
|
735 |
|
|
function void cmd_lst::print_str_wvar();
|
736 |
|
|
|
737 |
|
|
integer len;
|
738 |
|
|
integer vlen;
|
739 |
|
|
integer v;
|
740 |
|
|
integer i = 0;
|
741 |
|
|
integer j = 0;
|
742 |
|
|
integer val;
|
743 |
|
|
string sval;
|
744 |
|
|
string tmp;
|
745 |
|
|
string tmpv;
|
746 |
|
|
string vari;
|
747 |
|
|
string varv;
|
748 |
|
|
lst_item lvar;
|
749 |
|
|
|
750 |
|
|
if (this.lst_cmds.cmd_str == "") begin
|
751 |
|
|
return;
|
752 |
|
|
end
|
753 |
|
|
|
754 |
|
|
len = this.lst_cmds.cmd_str.len();
|
755 |
|
|
tmp = this.lst_cmds.cmd_str;
|
756 |
|
|
|
757 |
|
|
while (i < len) begin
|
758 |
|
|
if (tmp[i] == "$") begin
|
759 |
|
|
i++;
|
760 |
|
|
j = 0;
|
761 |
|
|
vari = "";
|
762 |
|
|
while (tmp[i] != " " && i < len) begin
|
763 |
|
|
vari = {vari,tmp[i]};
|
764 |
|
|
i++;
|
765 |
|
|
j++;
|
766 |
|
|
end
|
767 |
|
|
lvar = this.var_lst.find(vari);
|
768 |
|
|
val = lvar.val;
|
769 |
|
|
// convert var to str
|
770 |
|
|
$sformat(varv,"%x",val);
|
771 |
|
|
j = 0;
|
772 |
|
|
vlen = varv.len();
|
773 |
|
|
tmpv = varv;
|
774 |
|
|
// strip pre-padding
|
775 |
|
|
while(varv[j] == "0" && j < vlen) begin
|
776 |
|
|
j++;
|
777 |
|
|
v = tmpv.len();
|
778 |
|
|
tmpv = tmpv.substr(1, v-1);
|
779 |
|
|
end
|
780 |
|
|
|
781 |
|
|
sval = {sval, "0x", tmpv};
|
782 |
|
|
end else begin
|
783 |
|
|
sval = {sval,tmp[i]};
|
784 |
|
|
i++;
|
785 |
|
|
end
|
786 |
|
|
end
|
787 |
|
|
$display(sval);
|
788 |
|
|
|
789 |
|
|
endfunction
|
790 |
|
|
|
791 |
|
|
////////////////////////////////////////////////////////////
|
792 |
|
|
// print commands function: intened for debug and dev
|
793 |
|
|
function void cmd_lst::print_cmds();
|
794 |
|
|
tb_cmd tmp_cmd;
|
795 |
|
|
tmp_cmd = this.lst_cmds;
|
796 |
|
|
while(tmp_cmd != null) begin
|
797 |
|
|
tmp_cmd.print();
|
798 |
|
|
tmp_cmd = tmp_cmd.next;
|
799 |
|
|
end
|
800 |
|
|
//tmp_cmd.print();
|
801 |
|
|
$display("List Size: %s", this.lst_sz);
|
802 |
|
|
$display();
|
803 |
|
|
$display();
|
804 |
|
|
endfunction // print_cmds
|