Courtesy: Verification Academy:Sequences
A Configurable Sequence
The most generic way to configure sequences is to use the full
hierarchical name by default, but allow any other name to be used by the
creator of the sequence.
class my_bus_seq extends uvm_sequence #( my_bus_sequence_item );
string scope_name = "";
task body();
my_bus_config m_config;
if( scope_name == "" ) begin
scope_name = get_full_name(); // this is { sequencer.get_full_name() , get_name() }
end
if( !uvm_config_db #( my_bus_config )::get( null , scope_name , "my_bus_config" , m_config ) ) begin
`uvm_error(...)
end
endtask
endclass
|
Suppose
that we have a sequence called "initialization_sequence" running on the
sequencer on "uvm_test_top.env.sub_env.agent1.sequencer". This
scope_name in the code above by default is
"uvm_test_top.env.sub_env.agent1.sequencer.initialization_sequence".
The most usual use case for sequence configuration is that we
want to pick up the agent's configuration class which has been set on
the agent and all its children.
class sub_env extends uvm_env;
...
function void build_phase( uvm_phase phase );
...
my_bus_config agent1_config;
...
uvm_config_db #( my_bus_config )::set( this , "agent1*" , "my_bus_config" , agent1_config );
...
endfunction
task main_phase( uvm_phase phase );
my_bus_sequence seq = my_bus_sequence::type_id::create("my_bus_sequence");
seq.start( agent1.sequencer );
endtask
...
endclass
|
Since
we have used the sub_env as the context, the set and the default get in
the configurable sequence will match and as a result the sequence will
have access to the agent's configuration object.
Per Sequence Configuration
We can use the default mode of the configurable sequence above to
configure distinct sequences differently, although we can only do this
if the names of the sequences are different.
For example, the environment class might look something like this:
class sub_env extends uvm_env;
...
function void build_phase( uvm_phase phase );
...
my_bus_config agent1_config , agent1_error_config;
...
agent1_config.enable_error_injection = 0;
agent1_error_config.enable_error_injection =10;
// most sequences do not enable error injection
uvm_config_db #( my_bus_config )::set( this , "agent1*" , "my_bus_config" , agent1_config );
// sequences with "error" in their name will enable error injection
uvm_config_db #( my_bus_config )::set( this , "agent1.sequencer.error*" , "my_bus_config" , agent1_error_config );
...
endfunction
task main_phase( uvm_phase phase );
my_bus_sequence normal_seq = my_bus_sequence::type_id::create("normal_seq");
my_bus_sequence error_seq = my_bus_sequence::type_id::create("error_seq");
normal_seq.start( agent1.sequencer );
error_seq.start( agent1.sequencer );
endtask
...
endclass
|
Since
the configurable sequence uses the sequence name to do a get, the
normal sequence will pick up the configuration which does not enable
error injection while the error sequence will pick up the error
configuration.
Ignoring the Component Hierarchy Altogether
It is quite possible to completely ignore the component hierarchy
when configuring sequences. This has the advantage that we can in effect
define behavioural scopes which are only intended for configuring
sequences, and we can keep these behavioural scopes completely separate
from the component hierarchy. The configurable sequence described above
will work in this context as well as those above which are based on the
component hierarchy.
So for example in a virtual sequence we might do something like:
class my_virtual_sequence extends uvm_sequence #( uvm_sequence_item_base );
...
task body();
my_bus_sequence normal_seq = my_bus_sequence::type_id::create("normal_seq");
my_bus_sequence error_seq = my_bus_sequence::type_id::create("error_seq");
normal_seq.scope_name = "sequences::my_bus_config.no_error_injection";
error_seq.scope_name = "sequences::my_bus_config.enable_error_injection";
normal_seq.start( agent1.sequencer );
error_seq.start( agent1.sequencer );
endtask
...
endclass
|
The
downside to this freedom is that every sequence and component in this
testbench has to agree on the naming scheme, or at least be flexible
enough to deal with this kind of arbitrary naming scheme. Since there is
no longer any guarantee of uniqueness for these scope names, there may
be some reuse problems when moving from block to integration level.
No comments:
Post a Comment