Tuesday, 4 November 2014

Inject error values into DUT using sequences - SERIES 1

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