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