//----------------------------------------------------------------------
// Copyright 2010-2011 Mentor Graphics Corporation
// Copyright 2011 Synopsys, Inc.
// Copyright 2013 Cadence Design 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.
//----------------------------------------------------------------------
typedef class [docs]uvm_sequence_library_cfg;
//
// CLASS: uvm_sequence_library
//
// The ~uvm_sequence_library~ is a sequence that contains a list of registered
// sequence types. It can be configured to create and execute these sequences
// any number of times using one of several modes of operation, including a
// user-defined mode.
//
// When started (as any other sequence), the sequence library will randomly
// select and execute a sequence from its ~sequences~ queue. If in
// <UVM_SEQ_LIB_RAND> mode, its <select_rand> property is randomized and used
// as an index into ~sequences~. When in <UVM_SEQ_LIB_RANDC> mode, the
// <select_randc> property is used. When in <UVM_SEQ_LIB_ITEM> mode, only
// sequence items of the ~REQ~ type are generated and executed--no sequences
// are executed. Finally, when in <UVM_SEQ_LIB_USER> mode, the
// <select_sequence> method is called to obtain the index for selecting the
// next sequence to start. Users can override this method in subtypes to
// implement custom selection algorithms.
//
// Creating a subtype of a sequence library requires invocation of the
// <`uvm_sequence_library_utils> macro in its declaration and calling
// the <init_sequence_library> method in its constructor. The macro
// and function are needed to populate the sequence library with any
// sequences that were statically registered with it or any of its base
// classes.
//
//| class my_seq_lib extends uvm_sequence_library #(my_item);
//| `uvm_object_utils(my_seq_lib)
//| `uvm_sequence_library_utils(my_seq_lib)
//| function new(string name="");
//| super.new(name);
//| init_sequence_library();
//| endfunction
//| ...
//| endclass
//
//------------------------------------------------------------------------------
class [docs]uvm_sequence_library #(type REQ=uvm_sequence_item,RSP=REQ) extends uvm_sequence #(REQ,RSP);
// Function: new
//
// Create a new instance of this class
//
extern function [docs]new(string name="");
// Function: get_type_name
//
// Get the type name of this class
//
extern virtual function string [docs]get_type_name();
//--------------------------
// Group: Sequence selection
//--------------------------
// Variable: selection_mode
//
// Specifies the mode used to select sequences for execution
//
// If you do not have access to an instance of the library,
// use the configuration resource interface.
//
// The following example sets the ~config_seq_lib~ as the default
// sequence for the 'main' phase on the sequencer to be
// located at "env.agent.sequencer"
// and set the selection mode to <UVM_SEQ_LIB_RANDC>. If the
// settings are being done from within a component, the first
// argument must be ~this~ and the second argument a path
// relative to that component.
//
//
//| uvm_config_db #(uvm_object_wrapper)::set(null,
//| "env.agent.sequencer.main_phase",
//| "default_sequence",
//| main_seq_lib::get_type());
//|
//| uvm_config_db #(uvm_sequence_lib_mode)::set(null,
//| "env.agent.sequencer.main_phase",
//| "default_sequence.selection_mode",
//| UVM_SEQ_LIB_RANDC);
//
// Alternatively, you may create an instance of the sequence library
// a priori, initialize all its parameters, randomize it, then set it
// to run as-is on the sequencer.
//
//| main_seq_lib my_seq_lib;
//| my_seq_lib = new("my_seq_lib");
//|
//| my_seq_lib.selection_mode = UVM_SEQ_LIB_RANDC;
//| my_seq_lib.min_random_count = 500;
//| my_seq_lib.max_random_count = 1000;
//| void'(my_seq_lib.randomize());
//|
//| uvm_config_db #(uvm_sequence_base)::set(null,
//| "env.agent.sequencer.main_phase",
//| "default_sequence",
//| my_seq_lib);
//|
//
uvm_sequence_lib_mode selection_mode;
// Variable: min_random_count
//
// Sets the minimum number of items to execute. Use the configuration
// mechanism to set. See <selection_mode> for an example.
//
int unsigned min_random_count=10;
// Variable: max_random_count
//
// Sets the maximum number of items to execute. Use the configuration
// mechanism to set. See <selection_mode> for an example.
//
//
int unsigned max_random_count=10;
// Variable: sequences_executed
//
// Indicates the number of sequences executed, not including the
// currently executing sequence, if any.
//
protected int unsigned sequences_executed;
// Variable: sequence_count
//
// Specifies the number of sequences to execute when this sequence
// library is started. If in <UVM_SEQ_LIB_ITEM> mode, specifies the
// number of sequence items that will be generated.
//
rand int unsigned sequence_count = 10;
// Variable: select_rand
//
// The index variable that is randomized to select the next sequence
// to execute when in UVM_SEQ_LIB_RAND mode
//
// Extensions may place additional constraints on this variable.
//
rand int unsigned select_rand;
// Variable: select_randc
//
// The index variable that is randomized to select the next sequence
// to execute when in UVM_SEQ_LIB_RANDC mode
//
// Extensions may place additional constraints on this variable.
//
randc bit [15:0] select_randc;
// Variable- seqs_distrib
//
//
//
protected int seqs_distrib[string] = '{default:0};
// Variable- sequences
//
// The container of all registered sequence types. For <sequence_count>
// times, this sequence library will randomly select and execute a
// sequence from this list of sequence types.
//
protected uvm_object_wrapper sequences[$];
// Constraint: valid_rand_selection
//
// Constrains <select_rand> to be a valid index into the ~sequences~ array
//
constraint valid_rand_selection {
select_rand inside {[0:sequences.size()-1]};
}
// Constraint: valid_randc_selection
//
// Constrains <select_randc> to be a valid index into the ~sequences~ array
//
constraint valid_randc_selection {
select_randc inside {[0:sequences.size()-1]};
}
// Constraint: valid_sequence_count
//
// Constrains <sequence_count> to lie within the range defined by
// <min_random_count> and <max_random_count>.
//
constraint valid_sequence_count {
sequence_count inside {[min_random_count:max_random_count]};
}
// Function: select_sequence
//
// Generates an index used to select the next sequence to execute.
// Overrides must return a value between 0 and ~max~, inclusive.
// Used only for <UVM_SEQ_LIB_USER> selection mode. The
// default implementation returns 0, incrementing on successive calls,
// wrapping back to 0 when reaching ~max~.
//
extern virtual function int unsigned [docs]select_sequence(int unsigned max);
//-----------------------------
// Group: Sequence registration
//-----------------------------
// Function: add_typewide_sequence
//
// Registers the provided sequence type with this sequence library
// type. The sequence type will be available for selection by all instances
// of this class. Sequence types already registered are silently ignored.
//
extern static function void [docs]add_typewide_sequence(uvm_object_wrapper seq_type);
// Function: add_typewide_sequences
//
// Registers the provided sequence types with this sequence library
// type. The sequence types will be available for selection by all instances
// of this class. Sequence types already registered are silently ignored.
//
extern static function void [docs]add_typewide_sequences(uvm_object_wrapper seq_types[$]);
// Function: add_sequence
//
// Registers the provided sequence type with this sequence library
// instance. Sequence types already registered are silently ignored.
//
extern function void [docs]add_sequence(uvm_object_wrapper seq_type);
// Function: add_sequences
//
// Registers the provided sequence types with this sequence library
// instance. Sequence types already registered are silently ignored.
//
extern virtual function void [docs]add_sequences(uvm_object_wrapper seq_types[$]);
// Function: remove_sequence
//
// Removes the given sequence type from this sequence library
// instance. If the type was registered statically, the sequence queues of
// all instances of this library will be updated accordingly.
// A warning is issued if the sequence is not registered.
//
extern virtual function void [docs]remove_sequence(uvm_object_wrapper seq_type);
// Function: get_sequences
//
//
// Append to the provided ~seq_types~ array the list of registered ~sequences~.
//
extern virtual function void [docs]get_sequences(ref uvm_object_wrapper seq_types[$]);
// Function: init_sequence_library
//
// All subtypes of this class must call init_sequence_library in its
// constructor.
extern function void [docs]init_sequence_library();
// Macro: uvm_sequence_library_utils
//
// All subtypes of this class must invoke the `uvm_sequence_library_utils
// macro.
//
//| class my_seq_lib extends uvm_sequence_library #(my_item);
//| `uvm_object_utils(my_seq_lib)
//| `uvm_sequence_library_utils(my_seq_lib)
//| function new(string name="");
//| super.new(name);
//| init_sequence_library();
//| endfunction
//| ...
//| endclass
//------------------------------------------
// PRIVATE - INTERNAL - NOT PART OF STANDARD
//------------------------------------------
`uvm_object_param_utils(uvm_sequence_library #(REQ,RSP))
typedef uvm_sequence_library #(REQ,RSP) this_type;
static const string type_name = "uvm_sequence_library #(REQ,RSP)";
static protected uvm_object_wrapper m_typewide_sequences[$];
bit m_abort;
extern static function bit m_static_check(uvm_object_wrapper seq_type);
extern static function bit m_check(uvm_object_wrapper seq_type, this_type lib);
extern function bit m_dyn_check(uvm_object_wrapper seq_type);
extern function void m_get_config();
extern static function bit m_add_typewide_sequence(uvm_object_wrapper seq_type);
extern virtual task [docs]execute(uvm_object_wrapper wrap);
extern virtual task [docs]body();
extern virtual function void [docs]do_print(uvm_printer printer);
extern function void pre_randomize();
endclass
//------------------------------------------------------------------------------
//
// Class: uvm_sequence_library_cfg
//
// A convenient container class for configuring all the sequence library
// parameters using a single ~set~ command.
//
//| uvm_sequence_library_cfg cfg;
//| cfg = new("seqlib_cfg", UVM_SEQ_LIB_RANDC, 1000, 2000);
//|
//| uvm_config_db #(uvm_sequence_library_cfg)::set(null,
//| "env.agent.sequencer.main_ph",
//| "default_sequence.config",
//| cfg);
//|
//------------------------------------------------------------------------------
class [docs]uvm_sequence_library_cfg extends uvm_object;
`uvm_object_utils(uvm_sequence_library_cfg)
uvm_sequence_lib_mode selection_mode;
int unsigned min_random_count;
int unsigned max_random_count;
function [docs]new(string name="",
uvm_sequence_lib_mode mode=UVM_SEQ_LIB_RAND,
int unsigned min=1,
int unsigned max=10);
super.new(name);
selection_mode = mode;
min_random_count = min;
max_random_count = max;
endfunction
endclass
//------------------------------------------------------------------------------
// IMPLEMENTATION
//------------------------------------------------------------------------------
// new
// ---
function uvm_sequence_library::new(string name="");
super.new(name);
init_sequence_library();
valid_rand_selection.constraint_mode(0);
valid_randc_selection.constraint_mode(0);
endfunction
// get_type_name
// -------------
function string uvm_sequence_library::get_type_name();
return type_name;
endfunction
// m_add_typewide_sequence
// -----------------------
function bit uvm_sequence_library::m_add_typewide_sequence(uvm_object_wrapper seq_type);
this_type::add_typewide_sequence(seq_type);
return 1;
endfunction
// add_typewide_sequence
// ---------------------
function void uvm_sequence_library::add_typewide_sequence(uvm_object_wrapper seq_type);
if (m_static_check(seq_type))
m_typewide_sequences.push_back(seq_type);
endfunction
// add_typewide_sequences
// ----------------------
function void uvm_sequence_library::add_typewide_sequences(uvm_object_wrapper seq_types[$]);
foreach (seq_types[i])
add_typewide_sequence(seq_types[i]);
endfunction
// add_sequence
// ------------
function void uvm_sequence_library::add_sequence(uvm_object_wrapper seq_type);
if (m_dyn_check(seq_type))
sequences.push_back(seq_type);
endfunction
// add_sequences
// -------------
function void uvm_sequence_library::add_sequences(uvm_object_wrapper seq_types[$]);
foreach (seq_types[i])
add_sequence(seq_types[i]);
endfunction
// remove_sequence
// ---------------
function void uvm_sequence_library::remove_sequence(uvm_object_wrapper seq_type);
foreach (sequences[i])
if (sequences[i] == seq_type) begin
sequences.delete(i);
return;
end
endfunction
// get_sequences
// -------------
function void uvm_sequence_library::get_sequences(ref uvm_object_wrapper seq_types[$]);
foreach (sequences[i])
seq_types.push_back(sequences[i]);
endfunction
// select_sequence
// ---------------
function int unsigned uvm_sequence_library::select_sequence(int unsigned max);
static int unsigned counter;
select_sequence = counter;
counter++;
if (counter >= max)
counter = 0;
endfunction
//----------//
// INTERNAL //
//----------//
// init_sequence_library
// ---------------------
function void uvm_sequence_library::init_sequence_library();
foreach (this_type::m_typewide_sequences[i])
sequences.push_back(this_type::m_typewide_sequences[i]);
endfunction
// m_static_check
// --------------
function bit uvm_sequence_library::m_static_check(uvm_object_wrapper seq_type);
if (!m_check(seq_type,null))
return 0;
foreach (m_typewide_sequences[i])
if (m_typewide_sequences[i] == seq_type)
return 0;
return 1;
endfunction
// m_dyn_check
// -----------
function bit uvm_sequence_library::m_dyn_check(uvm_object_wrapper seq_type);
if (!m_check(seq_type,this))
return 0;
foreach (sequences[i])
if (sequences[i] == seq_type)
return 0;
return 1;
endfunction
// m_check
// -------
function bit uvm_sequence_library::m_check(uvm_object_wrapper seq_type, this_type lib);
uvm_object obj;
uvm_sequence_base seq;
uvm_root top;
uvm_coreservice_t cs;
string name;
string typ;
obj = seq_type.create_object();
name = (lib == null) ? type_name : lib.get_full_name();
typ = (lib == null) ? type_name : lib.get_type_name();
cs = uvm_coreservice_t::get();
top = cs.get_root();
if (!$cast(seq, obj)) begin
`uvm_error_context("SEQLIB/BAD_SEQ_TYPE",
{"Object '",obj.get_type_name(),
"' is not a sequence. Cannot add to sequence library '",name,
"'"},top)
return 0;
end
return 1;
endfunction
// pre_randomize
// -------------
function void uvm_sequence_library::pre_randomize();
m_get_config();
endfunction
// m_get_config
// ------------
function void uvm_sequence_library::m_get_config();
uvm_sequence_library_cfg cfg;
string phase_name;
uvm_phase starting_phase = get_starting_phase();
if (starting_phase != null) begin
phase_name = {starting_phase.get_name(),"_phase"};
end
if (uvm_config_db #(uvm_sequence_library_cfg)::get(m_sequencer,
phase_name,
"default_sequence.config",
cfg) ) begin
selection_mode = cfg.selection_mode;
min_random_count = cfg.min_random_count;
max_random_count = cfg.max_random_count;
end
else begin
void'(uvm_config_db #(int unsigned)::get(m_sequencer,
phase_name,
"default_sequence.min_random_count",
min_random_count) );
void'(uvm_config_db #(int unsigned)::get(m_sequencer,
phase_name,
"default_sequence.max_random_count",
max_random_count) );
void'(uvm_config_db #(uvm_sequence_lib_mode)::get(m_sequencer,
phase_name,
"default_sequence.selection_mode",
selection_mode) );
end
if (max_random_count == 0) begin
`uvm_warning("SEQLIB/MAX_ZERO",
$sformatf("max_random_count (%0d) zero. Nothing will be done.",
max_random_count))
if (min_random_count > max_random_count)
min_random_count = max_random_count;
end
else if (min_random_count > max_random_count) begin
`uvm_error("SEQLIB/MIN_GT_MAX",
$sformatf("min_random_count (%0d) greater than max_random_count (%0d). Setting min to max.",
min_random_count,max_random_count))
min_random_count = max_random_count;
end
else begin
if (selection_mode == UVM_SEQ_LIB_ITEM) begin
uvm_sequencer #(REQ,RSP) seqr;
uvm_object_wrapper lhs = REQ::get_type();
uvm_object_wrapper rhs = uvm_sequence_item::get_type();
if (lhs == rhs) begin
`uvm_error("SEQLIB/BASE_ITEM", {"selection_mode cannot be UVM_SEQ_LIB_ITEM when ",
"the REQ type is the base uvm_sequence_item. Using UVM_SEQ_LIB_RAND mode"})
selection_mode = UVM_SEQ_LIB_RAND;
end
if (m_sequencer == null || !$cast(seqr,m_sequencer)) begin
`uvm_error("SEQLIB/VIRT_SEQ", {"selection_mode cannot be UVM_SEQ_LIB_ITEM when ",
"running as a virtual sequence. Using UVM_SEQ_LIB_RAND mode"})
selection_mode = UVM_SEQ_LIB_RAND;
end
end
end
endfunction
// body
// ----
task uvm_sequence_library::body();
uvm_object_wrapper wrap;
uvm_phase starting_phase = get_starting_phase();
if (m_sequencer == null) begin
`uvm_fatal("SEQLIB/VIRT_SEQ", {"Sequence library 'm_sequencer' handle is null; ",
" no current support for running as a virtual sequence."})
return;
end
if (sequences.size() == 0) begin
`uvm_error("SEQLIB/NOSEQS", "Sequence library does not contain any sequences. Did you forget to call init_sequence_library() in the constructor?")
return;
end
if (do_not_randomize)
m_get_config();
m_safe_raise_starting_phase({"starting sequence library ",get_full_name()," (", get_type_name(),")"});
`uvm_info("SEQLIB/START",
$sformatf("Starting sequence library %s in %s phase: %0d iterations in mode %s",
get_type_name(),
(starting_phase != null ? starting_phase.get_name() : "unknown"),
sequence_count, selection_mode.name()),UVM_LOW)
`uvm_info("SEQLIB/SPRINT",{"\n",sprint(uvm_default_table_printer)},UVM_FULL)
case (selection_mode)
UVM_SEQ_LIB_RAND: begin
valid_rand_selection.constraint_mode(1);
valid_sequence_count.constraint_mode(0);
for (int i=1; i<=sequence_count; i++) begin
if (!randomize(select_rand)) begin
`uvm_error("SEQLIB/RAND_FAIL", "Random sequence selection failed")
break;
end
else begin
wrap = sequences[select_rand];
end
execute(wrap);
end
valid_rand_selection.constraint_mode(0);
valid_sequence_count.constraint_mode(1);
end
UVM_SEQ_LIB_RANDC: begin
uvm_object_wrapper q[$];
valid_randc_selection.constraint_mode(1);
valid_sequence_count.constraint_mode(0);
for (int i=1; i<=sequence_count; i++) begin
if (!randomize(select_randc)) begin
`uvm_error("SEQLIB/RANDC_FAIL", "Random sequence selection failed")
break;
end
else begin
wrap = sequences[select_randc];
end
q.push_back(wrap);
end
valid_randc_selection.constraint_mode(0);
valid_sequence_count.constraint_mode(1);
foreach(q[i])
execute(q[i]);
valid_randc_selection.constraint_mode(0);
valid_sequence_count.constraint_mode(1);
end
UVM_SEQ_LIB_ITEM: begin
for (int i=1; i<=sequence_count; i++) begin
wrap = REQ::get_type();
execute(wrap);
end
end
UVM_SEQ_LIB_USER: begin
for (int i=1; i<=sequence_count; i++) begin
int user_selection;
user_selection = select_sequence(sequences.size()-1);
if (user_selection >= sequences.size()) begin
`uvm_error("SEQLIB/USER_FAIL", "User sequence selection out of range")
wrap = REQ::get_type();
end
else begin
wrap = sequences[user_selection];
end
execute(wrap);
end
end
default: begin
`uvm_fatal("SEQLIB/RAND_MODE",
$sformatf("Unknown random sequence selection mode: %0d",selection_mode))
end
endcase
`uvm_info("SEQLIB/END",{"Ending sequence library in phase ",
(starting_phase != null ? starting_phase.get_name() : "unknown")},UVM_LOW)
`uvm_info("SEQLIB/DSTRB",$sformatf("%p",seqs_distrib),UVM_HIGH)
m_safe_drop_starting_phase({"starting sequence library ",get_full_name()," (", get_type_name(),")"});
endtask
// execute
// -------
task uvm_sequence_library::execute(uvm_object_wrapper wrap);
uvm_object obj;
uvm_sequence_item seq_or_item;
uvm_sequence_base seq_base;
REQ req_item;
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
obj = factory.create_object_by_type(wrap,get_full_name(),
$sformatf("%s:%0d",wrap.get_type_name(),sequences_executed+1));
if (!$cast(seq_base, obj)) begin
// If we're executing an item (not a sequence)
if (!$cast(req_item, obj)) begin
// But it's not our item type (This can happen if we were parameterized with
// a pure virtual type, because we're getting get_type() from the base class)
`uvm_error("SEQLIB/WRONG_ITEM_TYPE", {"The item created by '", get_full_name(), "' when in 'UVM_SEQ_LIB_ITEM' mode doesn't match the REQ type which was passed in to the uvm_sequence_library#(REQ[,RSP]), this can happen if the REQ type which was passed in was a pure-virtual type. Either configure the factory overrides to properly generate items for this sequence library, or do not execute this sequence library in UVM_SEQ_LIB_ITEM mode."})
return;
end
end
void'($cast(seq_or_item,obj)); // already qualified,
`uvm_info("SEQLIB/EXEC",{"Executing ",(seq_or_item.is_item() ? "item " : "sequence "),seq_or_item.get_name(),
" (",seq_or_item.get_type_name(),")"},UVM_FULL)
seq_or_item.print_sequence_info = 1;
`uvm_rand_send(seq_or_item)
seqs_distrib[seq_or_item.get_type_name()] = seqs_distrib[seq_or_item.get_type_name()]+1;
sequences_executed++;
endtask
// do_print
// --------
function void uvm_sequence_library::do_print(uvm_printer printer);
printer.print_field_int("min_random_count",min_random_count,32,UVM_DEC,,"int unsigned");
printer.print_field_int("max_random_count",max_random_count,32,UVM_DEC,,"int unsigned");
printer.print_generic("selection_mode","uvm_sequence_lib_mode",32,selection_mode.name());
printer.print_field_int("sequence_count",sequence_count,32,UVM_DEC,,"int unsigned");
printer.print_array_header("typewide_sequences",m_typewide_sequences.size(),"queue_object_types");
foreach (m_typewide_sequences[i])
printer.print_generic($sformatf("[%0d]",i),"uvm_object_wrapper","-",m_typewide_sequences[i].get_type_name());
printer.print_array_footer();
printer.print_array_header("sequences",sequences.size(),"queue_object_types");
foreach (sequences[i])
printer.print_generic($sformatf("[%0d]",i),"uvm_object_wrapper","-",sequences[i].get_type_name());
printer.print_array_footer();
printer.print_array_header("seqs_distrib",seqs_distrib.num(),"as_int_string");
foreach (seqs_distrib[typ]) begin
printer.print_field_int({"[",typ,"]"},seqs_distrib[typ],32,,UVM_DEC,"int unsigned");
end
printer.print_array_footer();
endfunction