//
//------------------------------------------------------------------------------
// Copyright 2007-2011 Mentor Graphics Corporation
// Copyright 2007-2011 Cadence Design Systems, Inc.
// Copyright 2010 Synopsys, Inc.
// Copyright 2014 NVIDIA Corporation
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//------------------------------------------------------------------------------
// File: Miscellaneous Structures
//------------------------------------------------------------------------------
//
// Class: uvm_void
//
// The ~uvm_void~ class is the base class for all UVM classes. It is an abstract
// class with no data members or functions. It allows for generic containers of
// objects to be created, similar to a void pointer in the C programming
// language. User classes derived directly from ~uvm_void~ inherit none of the
// UVM functionality, but such classes may be placed in ~uvm_void~-typed
// containers along with other UVM objects.
//
//------------------------------------------------------------------------------
virtual class [docs]uvm_void;
endclass
// Append/prepend symbolic values for order-dependent APIs
typedef enum {UVM_APPEND, UVM_PREPEND} [docs]uvm_apprepend;
// Forward declaration since scope stack uses uvm_objects now
typedef class [docs]uvm_object;
typedef class [docs]uvm_coreservice_t;
typedef class [docs]uvm_factory;
typedef class [docs]uvm_config_db;
// m_uvm_config_obj_misc is an internal typedef for the uvm_misc.svh file
// to use. UVM users should use the uvm_config_object typedef
typedef uvm_config_db#(uvm_object) m_uvm_config_obj_misc;
//----------------------------------------------------------------------------
//
// CLASS- uvm_scope_stack
//
//----------------------------------------------------------------------------
class [docs]uvm_scope_stack;
local string m_arg;
local string m_stack[$];
// depth
// -----
function int [docs]depth();
return m_stack.size();
endfunction
// scope
// -----
function string [docs]get();
string v;
if(m_stack.size() == 0) return m_arg;
get = m_stack[0];
for(int i=1; i<m_stack.size(); ++i) begin
v = m_stack[i];
if(v != "" && (v[0] == "[" || v[0] == "(" || v[0] == "{"))
get = {get,v};
else
get = {get,".",v};
end
if(m_arg != "") begin
if(get != "")
get = {get, ".", m_arg};
else
get = m_arg;
end
endfunction
// scope_arg
// ---------
function string [docs]get_arg();
return m_arg;
endfunction
// set_scope
// ---------
function void [docs]set (string s);
m_stack.delete();
m_stack.push_back(s);
m_arg = "";
endfunction
// down
// ----
function void [docs]down (string s);
m_stack.push_back(s);
m_arg = "";
endfunction
// down_element
// ------------
function void [docs]down_element (int element);
m_stack.push_back($sformatf("[%0d]",element));
m_arg = "";
endfunction
// up_element
// ------------
function void [docs]up_element ();
string s;
if(!m_stack.size())
return;
s = m_stack.pop_back();
if(s != "" && s[0] != "[")
m_stack.push_back(s);
endfunction
// up
// --
function void [docs]up (byte separator =".");
bit found;
string s;
while(m_stack.size() && !found ) begin
s = m_stack.pop_back();
if(separator == ".") begin
if (s == "" || (s[0] != "[" && s[0] != "(" && s[0] != "{"))
found = 1;
end
else begin
if(s != "" && s[0] == separator)
found = 1;
end
end
m_arg = "";
endfunction
// set_arg
// -------
function void [docs]set_arg (string arg);
if(arg=="") return;
m_arg = arg;
endfunction
// set_arg_element
// ---------------
function void [docs]set_arg_element (string arg, int ele);
string tmp_value_str;
tmp_value_str.itoa(ele);
m_arg = {arg, "[", tmp_value_str, "]"};
endfunction
// unset_arg
// ---------
function void [docs]unset_arg (string arg);
if(arg == m_arg)
m_arg = "";
endfunction
endclass
//------------------------------------------------------------------------------
//
// CLASS- uvm_status_container
//
// Internal class to contain status information for automation methods.
//
//------------------------------------------------------------------------------
class [docs]uvm_status_container;
//The clone setting is used by the set/get config to know if cloning is on.
bit clone = 1;
//Information variables used by the macro functions for storage.
bit warning;
bit status;
uvm_bitstream_t bitstream;
int intv;
int element;
string stringv;
string scratch1;
string scratch2;
string key;
uvm_object object;
bit array_warning_done;
static bit field_array[string];
static bit print_matches;
function void [docs]do_field_check(string field, uvm_object obj);
`ifdef UVM_ENABLE_FIELD_CHECKS
if (field_array.exists(field))
uvm_report_error("MLTFLD", $sformatf("Field %s is defined multiple times in type '%s'",
field, obj.get_type_name()), UVM_NONE);
`endif
field_array[field] = 1;
endfunction
function string [docs]get_function_type (int what);
case (what)
UVM_COPY: return "copy";
UVM_COMPARE: return "compare";
UVM_PRINT: return "print";
UVM_RECORD: return "record";
UVM_PACK: return "pack";
UVM_UNPACK: return "unpack";
UVM_FLAGS: return "get_flags";
UVM_SETINT: return "set";
UVM_SETOBJ: return "set_object";
UVM_SETSTR: return "set_string";
default: return "unknown";
endcase
endfunction
// The scope stack is used for messages that are emitted by policy classes.
uvm_scope_stack scope = new;
function string [docs]get_full_scope_arg ();
get_full_scope_arg = scope.get();
endfunction
//Used for checking cycles. When a data function is entered, if the depth is
//non-zero, then then the existeance of the object in the map means that a
//cycle has occured and the function should immediately exit. When the
//function exits, it should reset the cycle map so that there is no memory
//leak.
bit cycle_check[uvm_object];
//These are the policy objects currently in use. The policy object gets set
//when a function starts up. The macros use this.
uvm_comparer comparer;
uvm_packer packer;
uvm_recorder recorder;
uvm_printer printer;
// utility function used to perform a cycle check when config setting are pushed
// to uvm_objects. the function has to look at the current object stack representing
// the call stack of all __m_uvm_field_automation() invocations.
// it is a only a cycle if the previous __m_uvm_field_automation call scope
// is not identical with the current scope AND the scope is already present in the
// object stack
uvm_object m_uvm_cycle_scopes[$];
function bit m_do_cycle_check(uvm_object scope);
uvm_object l = (m_uvm_cycle_scopes.size()==0) ? null : m_uvm_cycle_scopes[$];
// we have been in this scope before (but actually right before so assuming a super/derived context of the same object)
if(l == scope)
begin
m_uvm_cycle_scopes.push_back(scope);
return 0;
end
else
begin
// now check if we have already been in this scope before
uvm_object m[$] = m_uvm_cycle_scopes.find_first(item) with (item == scope);
if(m.size()!=0) begin
return 1; // detected a cycle
end
else begin
m_uvm_cycle_scopes.push_back(scope);
return 0;
end
end
endfunction
endclass
// Variable- uvm_global_random_seed
//
// Create a seed which is based off of the global seed which can be used to seed
// srandom processes but will change if the command line seed setting is
// changed.
//
int unsigned uvm_global_random_seed = $urandom;
// Class- uvm_seed_map
//
// This map is a seed map that can be used to update seeds. The update
// is done automatically by the seed hashing routine. The seed_table_lookup
// uses an instance name lookup and the seed_table inside a given map
// uses a type name for the lookup.
//
class [docs]uvm_seed_map;
int unsigned seed_table [string];
int unsigned count [string];
endclass
uvm_seed_map uvm_random_seed_table_lookup [string];
//------------------------------------------------------------------------------
// Internal utility functions
//------------------------------------------------------------------------------
// Function- uvm_instance_scope
//
// A function that returns the scope that the UVM library lives in, either
// an instance, a module, or a package.
//
function string [docs]uvm_instance_scope();
byte c;
int pos;
//first time through the scope is ~null~ and we need to calculate, afterwards it
//is correctly set.
if(uvm_instance_scope != "")
return uvm_instance_scope;
$swrite(uvm_instance_scope, "%m");
//remove the extraneous .uvm_instance_scope piece or ::uvm_instance_scope
pos = uvm_instance_scope.len()-1;
c = uvm_instance_scope[pos];
while(pos && (c != ".") && (c != ":"))
c = uvm_instance_scope[--pos];
if(pos == 0)
uvm_report_error("SCPSTR", $sformatf("Illegal name %s in scope string",uvm_instance_scope));
uvm_instance_scope = uvm_instance_scope.substr(0,pos);
endfunction
// Function- uvm_oneway_hash
//
// A one-way hash function that is useful for creating srandom seeds. An
// unsigned int value is generated from the string input. An initial seed can
// be used to seed the hash, if not supplied the uvm_global_random_seed
// value is used. Uses a CRC like functionality to minimize collisions.
//
parameter UVM_STR_CRC_POLYNOMIAL = 32'h04c11db6;
function int unsigned [docs]uvm_oneway_hash ( string string_in, int unsigned seed=0 );
bit msb;
bit [7:0] current_byte;
bit [31:0] crc1;
if(!seed) seed = uvm_global_random_seed;
uvm_oneway_hash = seed;
crc1 = 32'hffffffff;
for (int _byte=0; _byte < string_in.len(); _byte++) begin
current_byte = string_in[_byte];
if (current_byte == 0) break;
for (int _bit=0; _bit < 8; _bit++) begin
msb = crc1[31];
crc1 <<= 1;
if (msb ^ current_byte[_bit]) begin
crc1 ^= UVM_STR_CRC_POLYNOMIAL;
crc1[0] = 1;
end
end
end
uvm_oneway_hash += ~{crc1[7:0], crc1[15:8], crc1[23:16], crc1[31:24]};
endfunction
// Function- uvm_create_random_seed
//
// Creates a random seed and updates the seed map so that if the same string
// is used again, a new value will be generated. The inst_id is used to hash
// by instance name and get a map of type name hashes which the type_id uses
// for its lookup.
function int unsigned [docs]uvm_create_random_seed ( string type_id, string inst_id="" );
uvm_seed_map seed_map;
if(inst_id == "")
inst_id = "__global__";
if(!uvm_random_seed_table_lookup.exists(inst_id))
uvm_random_seed_table_lookup[inst_id] = new;
seed_map = uvm_random_seed_table_lookup[inst_id];
type_id = {uvm_instance_scope(),type_id};
if(!seed_map.seed_table.exists(type_id)) begin
seed_map.seed_table[type_id] = uvm_oneway_hash ({type_id,"::",inst_id}, uvm_global_random_seed);
end
if (!seed_map.count.exists(type_id)) begin
seed_map.count[type_id] = 0;
end
//can't just increment, otherwise too much chance for collision, so
//randomize the seed using the last seed as the seed value. Check if
//the seed has been used before and if so increment it.
seed_map.seed_table[type_id] = seed_map.seed_table[type_id]+seed_map.count[type_id];
seed_map.count[type_id]++;
return seed_map.seed_table[type_id];
endfunction
// Function- uvm_object_value_str
//
//
function string [docs]uvm_object_value_str(uvm_object v);
if (v == null)
return "<null>";
uvm_object_value_str.itoa(v.get_inst_id());
uvm_object_value_str = {"@",uvm_object_value_str};
endfunction
// Function- uvm_leaf_scope
//
//
function string [docs]uvm_leaf_scope (string full_name, byte scope_separator = ".");
byte bracket_match;
int pos;
int bmatches;
bmatches = 0;
case(scope_separator)
"[": bracket_match = "]";
"(": bracket_match = ")";
"<": bracket_match = ">";
"{": bracket_match = "}";
default: bracket_match = "";
endcase
//Only use bracket matching if the input string has the end match
if(bracket_match != "" && bracket_match != full_name[full_name.len()-1])
bracket_match = "";
for(pos=full_name.len()-1; pos>0; --pos) begin
if(full_name[pos] == bracket_match) bmatches++;
else if(full_name[pos] == scope_separator) begin
bmatches--;
if(!bmatches || (bracket_match == "")) break;
end
end
if(pos) begin
if(scope_separator != ".") pos--;
uvm_leaf_scope = full_name.substr(pos+1,full_name.len()-1);
end
else begin
uvm_leaf_scope = full_name;
end
endfunction
// Function- uvm_bitstream_to_string
//
//
function string [docs]uvm_bitstream_to_string (uvm_bitstream_t value, int size,
uvm_radix_enum radix=UVM_NORADIX,
string radix_str="");
// sign extend & don't show radix for negative values
if (radix == UVM_DEC && value[size-1] === 1)
return $sformatf("%0d", value);
// TODO $countbits(value,'z) would be even better
if($isunknown(value)) begin
uvm_bitstream_t _t;
_t=0;
for(int idx=0;idx<size;idx++)
_t[idx]=value[idx];
value=_t;
end
else
value &= (1 << size)-1;
case(radix)
UVM_BIN: return $sformatf("%0s%0b", radix_str, value);
UVM_OCT: return $sformatf("%0s%0o", radix_str, value);
UVM_UNSIGNED: return $sformatf("%0s%0d", radix_str, value);
UVM_STRING: return $sformatf("%0s%0s", radix_str, value);
UVM_TIME: return $sformatf("%0s%0t", radix_str, value);
UVM_DEC: return $sformatf("%0s%0d", radix_str, value);
default: return $sformatf("%0s%0x", radix_str, value);
endcase
endfunction
// Function- uvm_integral_to_string
//
//
function string [docs]uvm_integral_to_string (uvm_integral_t value, int size,
uvm_radix_enum radix=UVM_NORADIX,
string radix_str="");
// sign extend & don't show radix for negative values
if (radix == UVM_DEC && value[size-1] === 1)
return $sformatf("%0d", value);
// TODO $countbits(value,'z) would be even better
if($isunknown(value)) begin
uvm_integral_t _t;
_t=0;
for(int idx=0;idx<size;idx++)
_t[idx]=value[idx];
value=_t;
end
else
value &= (1 << size)-1;
case(radix)
UVM_BIN: return $sformatf("%0s%0b", radix_str, value);
UVM_OCT: return $sformatf("%0s%0o", radix_str, value);
UVM_UNSIGNED: return $sformatf("%0s%0d", radix_str, value);
UVM_STRING: return $sformatf("%0s%0s", radix_str, value);
UVM_TIME: return $sformatf("%0s%0t", radix_str, value);
UVM_DEC: return $sformatf("%0s%0d", radix_str, value);
default: return $sformatf("%0s%0x", radix_str, value);
endcase
endfunction
// Backwards compat
function string [docs]uvm_vector_to_string(uvm_bitstream_t value, int size,
uvm_radix_enum radix=UVM_NORADIX,
string radix_str="");
return uvm_bitstream_to_string(value,size,radix,radix_str);
endfunction // uvm_vector_to_string
// Function- uvm_get_array_index_int
//
// The following functions check to see if a string is representing an array
// index, and if so, what the index is.
function int [docs]uvm_get_array_index_int(string arg, output bit is_wildcard);
int i;
uvm_get_array_index_int = 0;
is_wildcard = 1;
i = arg.len() - 1;
if(arg[i] == "]")
while(i > 0 && (arg[i] != "[")) begin
--i;
if((arg[i] == "*") || (arg[i] == "?")) i=0;
else if((arg[i] < "0") || (arg[i] > "9") && (arg[i] != "[")) begin
uvm_get_array_index_int = -1; //illegal integral index
i=0;
end
end
else begin
is_wildcard = 0;
return 0;
end
if(i>0) begin
arg = arg.substr(i+1, arg.len()-2);
uvm_get_array_index_int = arg.atoi();
is_wildcard = 0;
end
endfunction
// Function- uvm_get_array_index_string
//
//
function string [docs]uvm_get_array_index_string(string arg, output bit is_wildcard);
int i;
uvm_get_array_index_string = "";
is_wildcard = 1;
i = arg.len() - 1;
if(arg[i] == "]")
while(i > 0 && (arg[i] != "[")) begin
if((arg[i] == "*") || (arg[i] == "?")) i=0;
--i;
end
if(i>0) begin
uvm_get_array_index_string = arg.substr(i+1, arg.len()-2);
is_wildcard = 0;
end
endfunction
// Function- uvm_is_array
//
//
function bit [docs]uvm_is_array(string arg);
return arg[arg.len()-1] == "]";
endfunction
// Function- uvm_has_wildcard
//
//
function automatic bit [docs]uvm_has_wildcard (string arg);
uvm_has_wildcard = 0;
//if it is a regex then return true
if( (arg.len() > 1) && (arg[0] == "/") && (arg[arg.len()-1] == "/") )
return 1;
//check if it has globs
foreach(arg[i])
if( (arg[i] == "*") || (arg[i] == "+") || (arg[i] == "?") )
uvm_has_wildcard = 1;
endfunction
typedef class [docs]uvm_component;
typedef class [docs]uvm_root;
typedef class [docs]uvm_report_object;
//------------------------------------------------------------------------------
// CLASS: uvm_utils #(TYPE,FIELD)
//
// This class contains useful template functions.
//
//------------------------------------------------------------------------------
class [docs]uvm_utils #(type TYPE=int, string FIELD="config");
typedef TYPE types_t[$];
// Function: find_all
//
// Recursively finds all component instances of the parameter type ~TYPE~,
// starting with the component given by ~start~. Uses <uvm_root::find_all>.
static function types_t [docs]find_all(uvm_component start);
uvm_component list[$];
types_t types;
uvm_root top;
uvm_coreservice_t cs;
cs = uvm_coreservice_t::get();
top = cs.get_root();
top.find_all("*",list,start);
foreach (list[i]) begin
TYPE typ;
if ($cast(typ,list[i]))
types.push_back(typ);
end
if (types.size() == 0) begin
`uvm_warning("find_type-no match",{"Instance of type '",TYPE::type_name,
" not found in component hierarchy beginning at ",start.get_full_name()})
end
return types;
endfunction
static function TYPE [docs]find(uvm_component start);
types_t types = find_all(start);
if (types.size() == 0)
return null;
if (types.size() > 1) begin
`uvm_warning("find_type-multi match",{"More than one instance of type '",TYPE::type_name,
" found in component hierarchy beginning at ",start.get_full_name()})
return null;
end
return types[0];
endfunction
static function TYPE [docs]create_type_by_name(string type_name, string contxt);
uvm_object obj;
TYPE typ;
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
obj = factory.create_object_by_name(type_name,contxt,type_name);
if (!$cast(typ,obj))
uvm_report_error("WRONG_TYPE",{"The type_name given '",type_name,
"' with context '",contxt,"' did not produce the expected type."});
return typ;
endfunction
// Function: get_config
//
// This method gets the object config of type ~TYPE~
// associated with component ~comp~.
// We check for the two kinds of error which may occur with this kind of
// operation.
static function TYPE [docs]get_config(uvm_component comp, bit is_fatal);
uvm_object obj;
TYPE cfg;
if (!m_uvm_config_obj_misc::get(comp,"",FIELD, obj)) begin
if (is_fatal)
comp.uvm_report_fatal("NO_SET_CFG", {"no set_config to field '", FIELD,
"' for component '",comp.get_full_name(),"'"},
UVM_MEDIUM, `uvm_file , `uvm_line );
else
comp.uvm_report_warning("NO_SET_CFG", {"no set_config to field '", FIELD,
"' for component '",comp.get_full_name(),"'"},
UVM_MEDIUM, `uvm_file , `uvm_line );
return null;
end
if (!$cast(cfg, obj)) begin
if (is_fatal)
comp.uvm_report_fatal( "GET_CFG_TYPE_FAIL",
{"set_config_object with field name ",FIELD,
" is not of type '",TYPE::type_name,"'"},
UVM_NONE , `uvm_file , `uvm_line );
else
comp.uvm_report_warning( "GET_CFG_TYPE_FAIL",
{"set_config_object with field name ",FIELD,
" is not of type '",TYPE::type_name,"'"},
UVM_NONE , `uvm_file , `uvm_line );
end
return cfg;
endfunction
endclass
`ifdef UVM_USE_PROCESS_CONTAINER
class process_container_c;
process p;
function new(process p_);
p=p_;
endfunction
endclass
`endif
// this is an internal function and provides a string join independent of a streaming pack
function automatic string m_uvm_string_queue_join(ref string i[$]);
`ifndef QUESTA
m_uvm_string_queue_join = {>>{i}};
`else
foreach(i[idx])
m_uvm_string_queue_join = {m_uvm_string_queue_join,i[idx]};
`endif
endfunction