1 |
16 |
HanySalah |
//
|
2 |
|
|
//------------------------------------------------------------------------------
|
3 |
|
|
// Copyright 2007-2011 Mentor Graphics Corporation
|
4 |
|
|
// Copyright 2007-2011 Cadence Design Systems, Inc.
|
5 |
|
|
// Copyright 2010 Synopsys, Inc.
|
6 |
|
|
// Copyright 2014 NVIDIA Corporation
|
7 |
|
|
// All Rights Reserved Worldwide
|
8 |
|
|
//
|
9 |
|
|
// Licensed under the Apache License, Version 2.0 (the
|
10 |
|
|
// "License"); you may not use this file except in
|
11 |
|
|
// compliance with the License. You may obtain a copy of
|
12 |
|
|
// the License at
|
13 |
|
|
//
|
14 |
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
15 |
|
|
//
|
16 |
|
|
// Unless required by applicable law or agreed to in
|
17 |
|
|
// writing, software distributed under the License is
|
18 |
|
|
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
19 |
|
|
// CONDITIONS OF ANY KIND, either express or implied. See
|
20 |
|
|
// the License for the specific language governing
|
21 |
|
|
// permissions and limitations under the License.
|
22 |
|
|
//------------------------------------------------------------------------------
|
23 |
|
|
|
24 |
|
|
// File: Miscellaneous Structures
|
25 |
|
|
|
26 |
|
|
//------------------------------------------------------------------------------
|
27 |
|
|
//
|
28 |
|
|
// Class: uvm_void
|
29 |
|
|
//
|
30 |
|
|
// The ~uvm_void~ class is the base class for all UVM classes. It is an abstract
|
31 |
|
|
// class with no data members or functions. It allows for generic containers of
|
32 |
|
|
// objects to be created, similar to a void pointer in the C programming
|
33 |
|
|
// language. User classes derived directly from ~uvm_void~ inherit none of the
|
34 |
|
|
// UVM functionality, but such classes may be placed in ~uvm_void~-typed
|
35 |
|
|
// containers along with other UVM objects.
|
36 |
|
|
//
|
37 |
|
|
//------------------------------------------------------------------------------
|
38 |
|
|
|
39 |
|
|
virtual class uvm_void;
|
40 |
|
|
endclass
|
41 |
|
|
|
42 |
|
|
// Append/prepend symbolic values for order-dependent APIs
|
43 |
|
|
typedef enum {UVM_APPEND, UVM_PREPEND} uvm_apprepend;
|
44 |
|
|
|
45 |
|
|
// Forward declaration since scope stack uses uvm_objects now
|
46 |
|
|
typedef class uvm_object;
|
47 |
|
|
|
48 |
|
|
typedef class uvm_coreservice_t;
|
49 |
|
|
typedef class uvm_factory;
|
50 |
|
|
|
51 |
|
|
typedef class uvm_config_db;
|
52 |
|
|
// m_uvm_config_obj_misc is an internal typedef for the uvm_misc.svh file
|
53 |
|
|
// to use. UVM users should use the uvm_config_object typedef
|
54 |
|
|
typedef uvm_config_db#(uvm_object) m_uvm_config_obj_misc;
|
55 |
|
|
|
56 |
|
|
|
57 |
|
|
//----------------------------------------------------------------------------
|
58 |
|
|
//
|
59 |
|
|
// CLASS- uvm_scope_stack
|
60 |
|
|
//
|
61 |
|
|
//----------------------------------------------------------------------------
|
62 |
|
|
|
63 |
|
|
class uvm_scope_stack;
|
64 |
|
|
local string m_arg;
|
65 |
|
|
local string m_stack[$];
|
66 |
|
|
|
67 |
|
|
// depth
|
68 |
|
|
// -----
|
69 |
|
|
|
70 |
|
|
function int depth();
|
71 |
|
|
return m_stack.size();
|
72 |
|
|
endfunction
|
73 |
|
|
|
74 |
|
|
|
75 |
|
|
// scope
|
76 |
|
|
// -----
|
77 |
|
|
|
78 |
|
|
function string get();
|
79 |
|
|
string v;
|
80 |
|
|
if(m_stack.size() == 0) return m_arg;
|
81 |
|
|
get = m_stack[0];
|
82 |
|
|
for(int i=1; i
|
83 |
|
|
v = m_stack[i];
|
84 |
|
|
if(v != "" && (v[0] == "[" || v[0] == "(" || v[0] == "{"))
|
85 |
|
|
get = {get,v};
|
86 |
|
|
else
|
87 |
|
|
get = {get,".",v};
|
88 |
|
|
end
|
89 |
|
|
if(m_arg != "") begin
|
90 |
|
|
if(get != "")
|
91 |
|
|
get = {get, ".", m_arg};
|
92 |
|
|
else
|
93 |
|
|
get = m_arg;
|
94 |
|
|
end
|
95 |
|
|
endfunction
|
96 |
|
|
|
97 |
|
|
|
98 |
|
|
// scope_arg
|
99 |
|
|
// ---------
|
100 |
|
|
|
101 |
|
|
function string get_arg();
|
102 |
|
|
return m_arg;
|
103 |
|
|
endfunction
|
104 |
|
|
|
105 |
|
|
|
106 |
|
|
// set_scope
|
107 |
|
|
// ---------
|
108 |
|
|
|
109 |
|
|
function void set (string s);
|
110 |
|
|
m_stack.delete();
|
111 |
|
|
|
112 |
|
|
m_stack.push_back(s);
|
113 |
|
|
m_arg = "";
|
114 |
|
|
endfunction
|
115 |
|
|
|
116 |
|
|
|
117 |
|
|
// down
|
118 |
|
|
// ----
|
119 |
|
|
|
120 |
|
|
function void down (string s);
|
121 |
|
|
m_stack.push_back(s);
|
122 |
|
|
m_arg = "";
|
123 |
|
|
endfunction
|
124 |
|
|
|
125 |
|
|
|
126 |
|
|
// down_element
|
127 |
|
|
// ------------
|
128 |
|
|
|
129 |
|
|
function void down_element (int element);
|
130 |
|
|
m_stack.push_back($sformatf("[%0d]",element));
|
131 |
|
|
m_arg = "";
|
132 |
|
|
endfunction
|
133 |
|
|
|
134 |
|
|
|
135 |
|
|
// up_element
|
136 |
|
|
// ------------
|
137 |
|
|
|
138 |
|
|
function void up_element ();
|
139 |
|
|
string s;
|
140 |
|
|
if(!m_stack.size())
|
141 |
|
|
return;
|
142 |
|
|
s = m_stack.pop_back();
|
143 |
|
|
if(s != "" && s[0] != "[")
|
144 |
|
|
m_stack.push_back(s);
|
145 |
|
|
endfunction
|
146 |
|
|
|
147 |
|
|
// up
|
148 |
|
|
// --
|
149 |
|
|
|
150 |
|
|
function void up (byte separator =".");
|
151 |
|
|
bit found;
|
152 |
|
|
string s;
|
153 |
|
|
while(m_stack.size() && !found ) begin
|
154 |
|
|
s = m_stack.pop_back();
|
155 |
|
|
if(separator == ".") begin
|
156 |
|
|
if (s == "" || (s[0] != "[" && s[0] != "(" && s[0] != "{"))
|
157 |
|
|
found = 1;
|
158 |
|
|
end
|
159 |
|
|
else begin
|
160 |
|
|
if(s != "" && s[0] == separator)
|
161 |
|
|
found = 1;
|
162 |
|
|
end
|
163 |
|
|
end
|
164 |
|
|
m_arg = "";
|
165 |
|
|
endfunction
|
166 |
|
|
|
167 |
|
|
|
168 |
|
|
// set_arg
|
169 |
|
|
// -------
|
170 |
|
|
|
171 |
|
|
function void set_arg (string arg);
|
172 |
|
|
if(arg=="") return;
|
173 |
|
|
m_arg = arg;
|
174 |
|
|
endfunction
|
175 |
|
|
|
176 |
|
|
|
177 |
|
|
// set_arg_element
|
178 |
|
|
// ---------------
|
179 |
|
|
|
180 |
|
|
function void set_arg_element (string arg, int ele);
|
181 |
|
|
string tmp_value_str;
|
182 |
|
|
tmp_value_str.itoa(ele);
|
183 |
|
|
m_arg = {arg, "[", tmp_value_str, "]"};
|
184 |
|
|
endfunction
|
185 |
|
|
|
186 |
|
|
|
187 |
|
|
// unset_arg
|
188 |
|
|
// ---------
|
189 |
|
|
|
190 |
|
|
function void unset_arg (string arg);
|
191 |
|
|
if(arg == m_arg)
|
192 |
|
|
m_arg = "";
|
193 |
|
|
endfunction
|
194 |
|
|
endclass
|
195 |
|
|
|
196 |
|
|
|
197 |
|
|
|
198 |
|
|
//------------------------------------------------------------------------------
|
199 |
|
|
//
|
200 |
|
|
// CLASS- uvm_status_container
|
201 |
|
|
//
|
202 |
|
|
// Internal class to contain status information for automation methods.
|
203 |
|
|
//
|
204 |
|
|
//------------------------------------------------------------------------------
|
205 |
|
|
|
206 |
|
|
class uvm_status_container;
|
207 |
|
|
//The clone setting is used by the set/get config to know if cloning is on.
|
208 |
|
|
bit clone = 1;
|
209 |
|
|
|
210 |
|
|
//Information variables used by the macro functions for storage.
|
211 |
|
|
bit warning;
|
212 |
|
|
bit status;
|
213 |
|
|
uvm_bitstream_t bitstream;
|
214 |
|
|
int intv;
|
215 |
|
|
int element;
|
216 |
|
|
string stringv;
|
217 |
|
|
string scratch1;
|
218 |
|
|
string scratch2;
|
219 |
|
|
string key;
|
220 |
|
|
uvm_object object;
|
221 |
|
|
bit array_warning_done;
|
222 |
|
|
|
223 |
|
|
static bit field_array[string];
|
224 |
|
|
|
225 |
|
|
static bit print_matches;
|
226 |
|
|
|
227 |
|
|
function void do_field_check(string field, uvm_object obj);
|
228 |
|
|
`ifdef UVM_ENABLE_FIELD_CHECKS
|
229 |
|
|
if (field_array.exists(field))
|
230 |
|
|
uvm_report_error("MLTFLD", $sformatf("Field %s is defined multiple times in type '%s'",
|
231 |
|
|
field, obj.get_type_name()), UVM_NONE);
|
232 |
|
|
`endif
|
233 |
|
|
field_array[field] = 1;
|
234 |
|
|
endfunction
|
235 |
|
|
|
236 |
|
|
|
237 |
|
|
function string get_function_type (int what);
|
238 |
|
|
case (what)
|
239 |
|
|
UVM_COPY: return "copy";
|
240 |
|
|
UVM_COMPARE: return "compare";
|
241 |
|
|
UVM_PRINT: return "print";
|
242 |
|
|
UVM_RECORD: return "record";
|
243 |
|
|
UVM_PACK: return "pack";
|
244 |
|
|
UVM_UNPACK: return "unpack";
|
245 |
|
|
UVM_FLAGS: return "get_flags";
|
246 |
|
|
UVM_SETINT: return "set";
|
247 |
|
|
UVM_SETOBJ: return "set_object";
|
248 |
|
|
UVM_SETSTR: return "set_string";
|
249 |
|
|
default: return "unknown";
|
250 |
|
|
endcase
|
251 |
|
|
endfunction
|
252 |
|
|
|
253 |
|
|
|
254 |
|
|
|
255 |
|
|
// The scope stack is used for messages that are emitted by policy classes.
|
256 |
|
|
uvm_scope_stack scope = new;
|
257 |
|
|
|
258 |
|
|
function string get_full_scope_arg ();
|
259 |
|
|
get_full_scope_arg = scope.get();
|
260 |
|
|
endfunction
|
261 |
|
|
|
262 |
|
|
//Used for checking cycles. When a data function is entered, if the depth is
|
263 |
|
|
//non-zero, then then the existeance of the object in the map means that a
|
264 |
|
|
//cycle has occured and the function should immediately exit. When the
|
265 |
|
|
//function exits, it should reset the cycle map so that there is no memory
|
266 |
|
|
//leak.
|
267 |
|
|
bit cycle_check[uvm_object];
|
268 |
|
|
|
269 |
|
|
//These are the policy objects currently in use. The policy object gets set
|
270 |
|
|
//when a function starts up. The macros use this.
|
271 |
|
|
uvm_comparer comparer;
|
272 |
|
|
uvm_packer packer;
|
273 |
|
|
uvm_recorder recorder;
|
274 |
|
|
uvm_printer printer;
|
275 |
|
|
|
276 |
|
|
// utility function used to perform a cycle check when config setting are pushed
|
277 |
|
|
// to uvm_objects. the function has to look at the current object stack representing
|
278 |
|
|
// the call stack of all __m_uvm_field_automation() invocations.
|
279 |
|
|
// it is a only a cycle if the previous __m_uvm_field_automation call scope
|
280 |
|
|
// is not identical with the current scope AND the scope is already present in the
|
281 |
|
|
// object stack
|
282 |
|
|
uvm_object m_uvm_cycle_scopes[$];
|
283 |
|
|
function bit m_do_cycle_check(uvm_object scope);
|
284 |
|
|
uvm_object l = (m_uvm_cycle_scopes.size()==0) ? null : m_uvm_cycle_scopes[$];
|
285 |
|
|
|
286 |
|
|
// we have been in this scope before (but actually right before so assuming a super/derived context of the same object)
|
287 |
|
|
if(l == scope)
|
288 |
|
|
begin
|
289 |
|
|
m_uvm_cycle_scopes.push_back(scope);
|
290 |
|
|
return 0;
|
291 |
|
|
end
|
292 |
|
|
else
|
293 |
|
|
begin
|
294 |
|
|
// now check if we have already been in this scope before
|
295 |
|
|
uvm_object m[$] = m_uvm_cycle_scopes.find_first(item) with (item == scope);
|
296 |
|
|
if(m.size()!=0) begin
|
297 |
|
|
return 1; // detected a cycle
|
298 |
|
|
end
|
299 |
|
|
else begin
|
300 |
|
|
m_uvm_cycle_scopes.push_back(scope);
|
301 |
|
|
return 0;
|
302 |
|
|
end
|
303 |
|
|
end
|
304 |
|
|
endfunction
|
305 |
|
|
endclass
|
306 |
|
|
|
307 |
|
|
// Variable- uvm_global_random_seed
|
308 |
|
|
//
|
309 |
|
|
// Create a seed which is based off of the global seed which can be used to seed
|
310 |
|
|
// srandom processes but will change if the command line seed setting is
|
311 |
|
|
// changed.
|
312 |
|
|
//
|
313 |
|
|
int unsigned uvm_global_random_seed = $urandom;
|
314 |
|
|
|
315 |
|
|
|
316 |
|
|
// Class- uvm_seed_map
|
317 |
|
|
//
|
318 |
|
|
// This map is a seed map that can be used to update seeds. The update
|
319 |
|
|
// is done automatically by the seed hashing routine. The seed_table_lookup
|
320 |
|
|
// uses an instance name lookup and the seed_table inside a given map
|
321 |
|
|
// uses a type name for the lookup.
|
322 |
|
|
//
|
323 |
|
|
class uvm_seed_map;
|
324 |
|
|
int unsigned seed_table [string];
|
325 |
|
|
int unsigned count [string];
|
326 |
|
|
endclass
|
327 |
|
|
|
328 |
|
|
uvm_seed_map uvm_random_seed_table_lookup [string];
|
329 |
|
|
|
330 |
|
|
|
331 |
|
|
//------------------------------------------------------------------------------
|
332 |
|
|
// Internal utility functions
|
333 |
|
|
//------------------------------------------------------------------------------
|
334 |
|
|
|
335 |
|
|
// Function- uvm_instance_scope
|
336 |
|
|
//
|
337 |
|
|
// A function that returns the scope that the UVM library lives in, either
|
338 |
|
|
// an instance, a module, or a package.
|
339 |
|
|
//
|
340 |
|
|
function string uvm_instance_scope();
|
341 |
|
|
byte c;
|
342 |
|
|
int pos;
|
343 |
|
|
//first time through the scope is ~null~ and we need to calculate, afterwards it
|
344 |
|
|
//is correctly set.
|
345 |
|
|
|
346 |
|
|
if(uvm_instance_scope != "")
|
347 |
|
|
return uvm_instance_scope;
|
348 |
|
|
|
349 |
|
|
$swrite(uvm_instance_scope, "%m");
|
350 |
|
|
//remove the extraneous .uvm_instance_scope piece or ::uvm_instance_scope
|
351 |
|
|
pos = uvm_instance_scope.len()-1;
|
352 |
|
|
c = uvm_instance_scope[pos];
|
353 |
|
|
while(pos && (c != ".") && (c != ":"))
|
354 |
|
|
c = uvm_instance_scope[--pos];
|
355 |
|
|
if(pos == 0)
|
356 |
|
|
uvm_report_error("SCPSTR", $sformatf("Illegal name %s in scope string",uvm_instance_scope));
|
357 |
|
|
uvm_instance_scope = uvm_instance_scope.substr(0,pos);
|
358 |
|
|
endfunction
|
359 |
|
|
|
360 |
|
|
|
361 |
|
|
// Function- uvm_oneway_hash
|
362 |
|
|
//
|
363 |
|
|
// A one-way hash function that is useful for creating srandom seeds. An
|
364 |
|
|
// unsigned int value is generated from the string input. An initial seed can
|
365 |
|
|
// be used to seed the hash, if not supplied the uvm_global_random_seed
|
366 |
|
|
// value is used. Uses a CRC like functionality to minimize collisions.
|
367 |
|
|
//
|
368 |
|
|
parameter UVM_STR_CRC_POLYNOMIAL = 32'h04c11db6;
|
369 |
|
|
function int unsigned uvm_oneway_hash ( string string_in, int unsigned seed=0 );
|
370 |
|
|
bit msb;
|
371 |
|
|
bit [7:0] current_byte;
|
372 |
|
|
bit [31:0] crc1;
|
373 |
|
|
|
374 |
|
|
if(!seed) seed = uvm_global_random_seed;
|
375 |
|
|
uvm_oneway_hash = seed;
|
376 |
|
|
|
377 |
|
|
crc1 = 32'hffffffff;
|
378 |
|
|
for (int _byte=0; _byte < string_in.len(); _byte++) begin
|
379 |
|
|
current_byte = string_in[_byte];
|
380 |
|
|
if (current_byte == 0) break;
|
381 |
|
|
for (int _bit=0; _bit < 8; _bit++) begin
|
382 |
|
|
msb = crc1[31];
|
383 |
|
|
crc1 <<= 1;
|
384 |
|
|
if (msb ^ current_byte[_bit]) begin
|
385 |
|
|
crc1 ^= UVM_STR_CRC_POLYNOMIAL;
|
386 |
|
|
crc1[0] = 1;
|
387 |
|
|
end
|
388 |
|
|
end
|
389 |
|
|
end
|
390 |
|
|
uvm_oneway_hash += ~{crc1[7:0], crc1[15:8], crc1[23:16], crc1[31:24]};
|
391 |
|
|
|
392 |
|
|
endfunction
|
393 |
|
|
|
394 |
|
|
|
395 |
|
|
// Function- uvm_create_random_seed
|
396 |
|
|
//
|
397 |
|
|
// Creates a random seed and updates the seed map so that if the same string
|
398 |
|
|
// is used again, a new value will be generated. The inst_id is used to hash
|
399 |
|
|
// by instance name and get a map of type name hashes which the type_id uses
|
400 |
|
|
// for its lookup.
|
401 |
|
|
|
402 |
|
|
function int unsigned uvm_create_random_seed ( string type_id, string inst_id="" );
|
403 |
|
|
uvm_seed_map seed_map;
|
404 |
|
|
|
405 |
|
|
if(inst_id == "")
|
406 |
|
|
inst_id = "__global__";
|
407 |
|
|
|
408 |
|
|
if(!uvm_random_seed_table_lookup.exists(inst_id))
|
409 |
|
|
uvm_random_seed_table_lookup[inst_id] = new;
|
410 |
|
|
seed_map = uvm_random_seed_table_lookup[inst_id];
|
411 |
|
|
|
412 |
|
|
type_id = {uvm_instance_scope(),type_id};
|
413 |
|
|
|
414 |
|
|
if(!seed_map.seed_table.exists(type_id)) begin
|
415 |
|
|
seed_map.seed_table[type_id] = uvm_oneway_hash ({type_id,"::",inst_id}, uvm_global_random_seed);
|
416 |
|
|
end
|
417 |
|
|
if (!seed_map.count.exists(type_id)) begin
|
418 |
|
|
seed_map.count[type_id] = 0;
|
419 |
|
|
end
|
420 |
|
|
|
421 |
|
|
//can't just increment, otherwise too much chance for collision, so
|
422 |
|
|
//randomize the seed using the last seed as the seed value. Check if
|
423 |
|
|
//the seed has been used before and if so increment it.
|
424 |
|
|
seed_map.seed_table[type_id] = seed_map.seed_table[type_id]+seed_map.count[type_id];
|
425 |
|
|
seed_map.count[type_id]++;
|
426 |
|
|
|
427 |
|
|
return seed_map.seed_table[type_id];
|
428 |
|
|
endfunction
|
429 |
|
|
|
430 |
|
|
|
431 |
|
|
// Function- uvm_object_value_str
|
432 |
|
|
//
|
433 |
|
|
//
|
434 |
|
|
function string uvm_object_value_str(uvm_object v);
|
435 |
|
|
if (v == null)
|
436 |
|
|
return "";
|
437 |
|
|
uvm_object_value_str.itoa(v.get_inst_id());
|
438 |
|
|
uvm_object_value_str = {"@",uvm_object_value_str};
|
439 |
|
|
endfunction
|
440 |
|
|
|
441 |
|
|
|
442 |
|
|
// Function- uvm_leaf_scope
|
443 |
|
|
//
|
444 |
|
|
//
|
445 |
|
|
function string uvm_leaf_scope (string full_name, byte scope_separator = ".");
|
446 |
|
|
byte bracket_match;
|
447 |
|
|
int pos;
|
448 |
|
|
int bmatches;
|
449 |
|
|
|
450 |
|
|
bmatches = 0;
|
451 |
|
|
case(scope_separator)
|
452 |
|
|
"[": bracket_match = "]";
|
453 |
|
|
"(": bracket_match = ")";
|
454 |
|
|
"<": bracket_match = ">";
|
455 |
|
|
"{": bracket_match = "}";
|
456 |
|
|
default: bracket_match = "";
|
457 |
|
|
endcase
|
458 |
|
|
|
459 |
|
|
//Only use bracket matching if the input string has the end match
|
460 |
|
|
if(bracket_match != "" && bracket_match != full_name[full_name.len()-1])
|
461 |
|
|
bracket_match = "";
|
462 |
|
|
|
463 |
|
|
for(pos=full_name.len()-1; pos>0; --pos) begin
|
464 |
|
|
if(full_name[pos] == bracket_match) bmatches++;
|
465 |
|
|
else if(full_name[pos] == scope_separator) begin
|
466 |
|
|
bmatches--;
|
467 |
|
|
if(!bmatches || (bracket_match == "")) break;
|
468 |
|
|
end
|
469 |
|
|
end
|
470 |
|
|
if(pos) begin
|
471 |
|
|
if(scope_separator != ".") pos--;
|
472 |
|
|
uvm_leaf_scope = full_name.substr(pos+1,full_name.len()-1);
|
473 |
|
|
end
|
474 |
|
|
else begin
|
475 |
|
|
uvm_leaf_scope = full_name;
|
476 |
|
|
end
|
477 |
|
|
endfunction
|
478 |
|
|
|
479 |
|
|
|
480 |
|
|
// Function- uvm_bitstream_to_string
|
481 |
|
|
//
|
482 |
|
|
//
|
483 |
|
|
function string uvm_bitstream_to_string (uvm_bitstream_t value, int size,
|
484 |
|
|
uvm_radix_enum radix=UVM_NORADIX,
|
485 |
|
|
string radix_str="");
|
486 |
|
|
// sign extend & don't show radix for negative values
|
487 |
|
|
if (radix == UVM_DEC && value[size-1] === 1)
|
488 |
|
|
return $sformatf("%0d", value);
|
489 |
|
|
|
490 |
|
|
// TODO $countbits(value,'z) would be even better
|
491 |
|
|
if($isunknown(value)) begin
|
492 |
|
|
uvm_bitstream_t _t;
|
493 |
|
|
_t=0;
|
494 |
|
|
for(int idx=0;idx
|
495 |
|
|
_t[idx]=value[idx];
|
496 |
|
|
value=_t;
|
497 |
|
|
end
|
498 |
|
|
else
|
499 |
|
|
value &= (1 << size)-1;
|
500 |
|
|
|
501 |
|
|
case(radix)
|
502 |
|
|
UVM_BIN: return $sformatf("%0s%0b", radix_str, value);
|
503 |
|
|
UVM_OCT: return $sformatf("%0s%0o", radix_str, value);
|
504 |
|
|
UVM_UNSIGNED: return $sformatf("%0s%0d", radix_str, value);
|
505 |
|
|
UVM_STRING: return $sformatf("%0s%0s", radix_str, value);
|
506 |
|
|
UVM_TIME: return $sformatf("%0s%0t", radix_str, value);
|
507 |
|
|
UVM_DEC: return $sformatf("%0s%0d", radix_str, value);
|
508 |
|
|
default: return $sformatf("%0s%0x", radix_str, value);
|
509 |
|
|
endcase
|
510 |
|
|
endfunction
|
511 |
|
|
|
512 |
|
|
// Function- uvm_integral_to_string
|
513 |
|
|
//
|
514 |
|
|
//
|
515 |
|
|
function string uvm_integral_to_string (uvm_integral_t value, int size,
|
516 |
|
|
uvm_radix_enum radix=UVM_NORADIX,
|
517 |
|
|
string radix_str="");
|
518 |
|
|
// sign extend & don't show radix for negative values
|
519 |
|
|
if (radix == UVM_DEC && value[size-1] === 1)
|
520 |
|
|
return $sformatf("%0d", value);
|
521 |
|
|
|
522 |
|
|
// TODO $countbits(value,'z) would be even better
|
523 |
|
|
if($isunknown(value)) begin
|
524 |
|
|
uvm_integral_t _t;
|
525 |
|
|
_t=0;
|
526 |
|
|
for(int idx=0;idx
|
527 |
|
|
_t[idx]=value[idx];
|
528 |
|
|
value=_t;
|
529 |
|
|
end
|
530 |
|
|
else
|
531 |
|
|
value &= (1 << size)-1;
|
532 |
|
|
|
533 |
|
|
case(radix)
|
534 |
|
|
UVM_BIN: return $sformatf("%0s%0b", radix_str, value);
|
535 |
|
|
UVM_OCT: return $sformatf("%0s%0o", radix_str, value);
|
536 |
|
|
UVM_UNSIGNED: return $sformatf("%0s%0d", radix_str, value);
|
537 |
|
|
UVM_STRING: return $sformatf("%0s%0s", radix_str, value);
|
538 |
|
|
UVM_TIME: return $sformatf("%0s%0t", radix_str, value);
|
539 |
|
|
UVM_DEC: return $sformatf("%0s%0d", radix_str, value);
|
540 |
|
|
default: return $sformatf("%0s%0x", radix_str, value);
|
541 |
|
|
endcase
|
542 |
|
|
endfunction
|
543 |
|
|
|
544 |
|
|
// Backwards compat
|
545 |
|
|
function string uvm_vector_to_string(uvm_bitstream_t value, int size,
|
546 |
|
|
uvm_radix_enum radix=UVM_NORADIX,
|
547 |
|
|
string radix_str="");
|
548 |
|
|
return uvm_bitstream_to_string(value,size,radix,radix_str);
|
549 |
|
|
endfunction // uvm_vector_to_string
|
550 |
|
|
|
551 |
|
|
// Function- uvm_get_array_index_int
|
552 |
|
|
//
|
553 |
|
|
// The following functions check to see if a string is representing an array
|
554 |
|
|
// index, and if so, what the index is.
|
555 |
|
|
|
556 |
|
|
function int uvm_get_array_index_int(string arg, output bit is_wildcard);
|
557 |
|
|
int i;
|
558 |
|
|
uvm_get_array_index_int = 0;
|
559 |
|
|
is_wildcard = 1;
|
560 |
|
|
i = arg.len() - 1;
|
561 |
|
|
if(arg[i] == "]")
|
562 |
|
|
while(i > 0 && (arg[i] != "[")) begin
|
563 |
|
|
--i;
|
564 |
|
|
if((arg[i] == "*") || (arg[i] == "?")) i=0;
|
565 |
|
|
else if((arg[i] < "0") || (arg[i] > "9") && (arg[i] != "[")) begin
|
566 |
|
|
uvm_get_array_index_int = -1; //illegal integral index
|
567 |
|
|
i=0;
|
568 |
|
|
end
|
569 |
|
|
end
|
570 |
|
|
else begin
|
571 |
|
|
is_wildcard = 0;
|
572 |
|
|
return 0;
|
573 |
|
|
end
|
574 |
|
|
|
575 |
|
|
if(i>0) begin
|
576 |
|
|
arg = arg.substr(i+1, arg.len()-2);
|
577 |
|
|
uvm_get_array_index_int = arg.atoi();
|
578 |
|
|
is_wildcard = 0;
|
579 |
|
|
end
|
580 |
|
|
endfunction
|
581 |
|
|
|
582 |
|
|
|
583 |
|
|
// Function- uvm_get_array_index_string
|
584 |
|
|
//
|
585 |
|
|
//
|
586 |
|
|
function string uvm_get_array_index_string(string arg, output bit is_wildcard);
|
587 |
|
|
int i;
|
588 |
|
|
uvm_get_array_index_string = "";
|
589 |
|
|
is_wildcard = 1;
|
590 |
|
|
i = arg.len() - 1;
|
591 |
|
|
if(arg[i] == "]")
|
592 |
|
|
while(i > 0 && (arg[i] != "[")) begin
|
593 |
|
|
if((arg[i] == "*") || (arg[i] == "?")) i=0;
|
594 |
|
|
--i;
|
595 |
|
|
end
|
596 |
|
|
if(i>0) begin
|
597 |
|
|
uvm_get_array_index_string = arg.substr(i+1, arg.len()-2);
|
598 |
|
|
is_wildcard = 0;
|
599 |
|
|
end
|
600 |
|
|
endfunction
|
601 |
|
|
|
602 |
|
|
|
603 |
|
|
// Function- uvm_is_array
|
604 |
|
|
//
|
605 |
|
|
//
|
606 |
|
|
function bit uvm_is_array(string arg);
|
607 |
|
|
return arg[arg.len()-1] == "]";
|
608 |
|
|
endfunction
|
609 |
|
|
|
610 |
|
|
|
611 |
|
|
// Function- uvm_has_wildcard
|
612 |
|
|
//
|
613 |
|
|
//
|
614 |
|
|
function automatic bit uvm_has_wildcard (string arg);
|
615 |
|
|
uvm_has_wildcard = 0;
|
616 |
|
|
|
617 |
|
|
//if it is a regex then return true
|
618 |
|
|
if( (arg.len() > 1) && (arg[0] == "/") && (arg[arg.len()-1] == "/") )
|
619 |
|
|
return 1;
|
620 |
|
|
|
621 |
|
|
//check if it has globs
|
622 |
|
|
foreach(arg[i])
|
623 |
|
|
if( (arg[i] == "*") || (arg[i] == "+") || (arg[i] == "?") )
|
624 |
|
|
uvm_has_wildcard = 1;
|
625 |
|
|
|
626 |
|
|
endfunction
|
627 |
|
|
|
628 |
|
|
|
629 |
|
|
typedef class uvm_component;
|
630 |
|
|
typedef class uvm_root;
|
631 |
|
|
typedef class uvm_report_object;
|
632 |
|
|
|
633 |
|
|
//------------------------------------------------------------------------------
|
634 |
|
|
// CLASS: uvm_utils #(TYPE,FIELD)
|
635 |
|
|
//
|
636 |
|
|
// This class contains useful template functions.
|
637 |
|
|
//
|
638 |
|
|
//------------------------------------------------------------------------------
|
639 |
|
|
|
640 |
|
|
class uvm_utils #(type TYPE=int, string FIELD="config");
|
641 |
|
|
|
642 |
|
|
typedef TYPE types_t[$];
|
643 |
|
|
|
644 |
|
|
// Function: find_all
|
645 |
|
|
//
|
646 |
|
|
// Recursively finds all component instances of the parameter type ~TYPE~,
|
647 |
|
|
// starting with the component given by ~start~. Uses .
|
648 |
|
|
|
649 |
|
|
static function types_t find_all(uvm_component start);
|
650 |
|
|
uvm_component list[$];
|
651 |
|
|
types_t types;
|
652 |
|
|
uvm_root top;
|
653 |
|
|
uvm_coreservice_t cs;
|
654 |
|
|
cs = uvm_coreservice_t::get();
|
655 |
|
|
top = cs.get_root();
|
656 |
|
|
top.find_all("*",list,start);
|
657 |
|
|
foreach (list[i]) begin
|
658 |
|
|
TYPE typ;
|
659 |
|
|
if ($cast(typ,list[i]))
|
660 |
|
|
types.push_back(typ);
|
661 |
|
|
end
|
662 |
|
|
if (types.size() == 0) begin
|
663 |
|
|
`uvm_warning("find_type-no match",{"Instance of type '",TYPE::type_name,
|
664 |
|
|
" not found in component hierarchy beginning at ",start.get_full_name()})
|
665 |
|
|
end
|
666 |
|
|
return types;
|
667 |
|
|
endfunction
|
668 |
|
|
|
669 |
|
|
static function TYPE find(uvm_component start);
|
670 |
|
|
types_t types = find_all(start);
|
671 |
|
|
if (types.size() == 0)
|
672 |
|
|
return null;
|
673 |
|
|
if (types.size() > 1) begin
|
674 |
|
|
`uvm_warning("find_type-multi match",{"More than one instance of type '",TYPE::type_name,
|
675 |
|
|
" found in component hierarchy beginning at ",start.get_full_name()})
|
676 |
|
|
return null;
|
677 |
|
|
end
|
678 |
|
|
return types[0];
|
679 |
|
|
endfunction
|
680 |
|
|
|
681 |
|
|
static function TYPE create_type_by_name(string type_name, string contxt);
|
682 |
|
|
uvm_object obj;
|
683 |
|
|
TYPE typ;
|
684 |
|
|
uvm_coreservice_t cs = uvm_coreservice_t::get();
|
685 |
|
|
uvm_factory factory=cs.get_factory();
|
686 |
|
|
|
687 |
|
|
obj = factory.create_object_by_name(type_name,contxt,type_name);
|
688 |
|
|
if (!$cast(typ,obj))
|
689 |
|
|
uvm_report_error("WRONG_TYPE",{"The type_name given '",type_name,
|
690 |
|
|
"' with context '",contxt,"' did not produce the expected type."});
|
691 |
|
|
return typ;
|
692 |
|
|
endfunction
|
693 |
|
|
|
694 |
|
|
|
695 |
|
|
// Function: get_config
|
696 |
|
|
//
|
697 |
|
|
// This method gets the object config of type ~TYPE~
|
698 |
|
|
// associated with component ~comp~.
|
699 |
|
|
// We check for the two kinds of error which may occur with this kind of
|
700 |
|
|
// operation.
|
701 |
|
|
|
702 |
|
|
static function TYPE get_config(uvm_component comp, bit is_fatal);
|
703 |
|
|
uvm_object obj;
|
704 |
|
|
TYPE cfg;
|
705 |
|
|
|
706 |
|
|
if (!m_uvm_config_obj_misc::get(comp,"",FIELD, obj)) begin
|
707 |
|
|
if (is_fatal)
|
708 |
|
|
comp.uvm_report_fatal("NO_SET_CFG", {"no set_config to field '", FIELD,
|
709 |
|
|
"' for component '",comp.get_full_name(),"'"},
|
710 |
|
|
UVM_MEDIUM, `uvm_file , `uvm_line );
|
711 |
|
|
else
|
712 |
|
|
comp.uvm_report_warning("NO_SET_CFG", {"no set_config to field '", FIELD,
|
713 |
|
|
"' for component '",comp.get_full_name(),"'"},
|
714 |
|
|
UVM_MEDIUM, `uvm_file , `uvm_line );
|
715 |
|
|
return null;
|
716 |
|
|
end
|
717 |
|
|
|
718 |
|
|
if (!$cast(cfg, obj)) begin
|
719 |
|
|
if (is_fatal)
|
720 |
|
|
comp.uvm_report_fatal( "GET_CFG_TYPE_FAIL",
|
721 |
|
|
{"set_config_object with field name ",FIELD,
|
722 |
|
|
" is not of type '",TYPE::type_name,"'"},
|
723 |
|
|
UVM_NONE , `uvm_file , `uvm_line );
|
724 |
|
|
else
|
725 |
|
|
comp.uvm_report_warning( "GET_CFG_TYPE_FAIL",
|
726 |
|
|
{"set_config_object with field name ",FIELD,
|
727 |
|
|
" is not of type '",TYPE::type_name,"'"},
|
728 |
|
|
UVM_NONE , `uvm_file , `uvm_line );
|
729 |
|
|
end
|
730 |
|
|
|
731 |
|
|
return cfg;
|
732 |
|
|
endfunction
|
733 |
|
|
endclass
|
734 |
|
|
|
735 |
|
|
`ifdef UVM_USE_PROCESS_CONTAINER
|
736 |
|
|
class process_container_c;
|
737 |
|
|
process p;
|
738 |
|
|
function new(process p_);
|
739 |
|
|
p=p_;
|
740 |
|
|
endfunction
|
741 |
|
|
endclass
|
742 |
|
|
`endif
|
743 |
|
|
|
744 |
|
|
|
745 |
|
|
// this is an internal function and provides a string join independent of a streaming pack
|
746 |
|
|
function automatic string m_uvm_string_queue_join(ref string i[$]);
|
747 |
|
|
`ifndef QUESTA
|
748 |
|
|
m_uvm_string_queue_join = {>>{i}};
|
749 |
|
|
`else
|
750 |
|
|
foreach(i[idx])
|
751 |
|
|
m_uvm_string_queue_join = {m_uvm_string_queue_join,i[idx]};
|
752 |
|
|
`endif
|
753 |
|
|
endfunction
|