Tuesday, 18 November 2014

Inject error values into DUT - SERIES 2

In SERIES 1, errors are driven by inserting error values into cfg_db and passing this instance of cfg_db into respective testcase.

Another method is to use nested transaction class in test class and override this nested class with original transaction class. this method provides encapsulation of error injection into that particular test. This can be understood with below discussion in verification academy forum.

***********************************************************************************
There are separate sequences running on multiple instances of UVC. In a testcase, I want to override the transaction item in particular instance of sequence. I tried the below, which is not working. Any clue ?
class baseseq extends uvm_sequence;
 
task body();
basetrans = trans::type_id::create ("trans");
start_item(trans);
trans.randomize();
finish_item(trans);
endtask
 
endclass
 
class basetest extends uvm_test;
 task run;
   foreach (seq[id]) begin      // Let's say id is from 0 to 4
     seq[id]=baseseq::type_id::create($sformatf("seq_%0d",id), ,get_full_name());
     seq[id].start(seqr[id]);
    end
 endtask
endclass
 
class mytest extends basetest;
 
 class errtrans extends basetrans;
   // additional functionalities
 endclass
 
 task run;
   foreach (seq[id]) begin
     seq[id]=baseseq::type_id::create($sformatf("seq_%0d",id), ,get_full_name());
     seq[id].start(seqr[id]);
    end
   basetrans::type_id:set_inst_override(errtrans:get_type(), {get_full_name,".seq_4"});
   // I expect the override type should effect from now, but is not happening !!
   foreach (seq[id]) begin
     seq[id]=baseseq::type_id::create($sformatf("seq_%0d",id), ,get_full_name());
     seq[id].start(seqr[id]);
    end
 endtask
endclass
 
**********************************************************************************************
Instance overrides just require the create() name of the instance to match the pattern of the override. You have an override that looks like it would be intended to override the sequence, not the transaction. It looks like you have followed most of the recommendations in the cookbook page Sequences/Overrides - just a couple of things need changed in your code to make it work:
(1) give your transaction instance some context when you create it in class baseseq, otherwise you can't easily match it with an instance override. Recommend you change the create() to add the 3rd context argument:

basetrans trans = basetrans::type_id::create("trans",,get_full_name());
                                                    ^^^^^^^^^^^^^^^^^
The transaction (that you wish to override) now has a context which is the get_full_name() OF THE SEQUENCE.
You need to match that up with (a) your create() of the sequence and (b) your instance override.
(2) in the sequence creation and override, use the get_full_name() of seqr[4], not of the test, and append the actual transaction name to the instance override (or a wildcard):

basetrans::type_id::set_inst_override(errtrans::get_type(), {seqr[4].get_full_name,".seq_4.trans"});
                                                             ^^^^^^^^                     ^^^^^^
    foreach (seq[id]) begin
      seq[id]=baseseq::type_id::create($sformatf("seq_%0d",id), ,seqr[id].get_full_name());
                                                                 ^^^^^^^^^
BTW kudos for using a NESTED CLASS for your definition of errtrans, inside your test. That is a great technique for keeping all aspects of a testcase together in one file, especially when the override is as simple as e.g. adding a random constraint on the base transaction. Just remember that class still needs a `uvm_object_utils so that the factory knows about it, and you need to ensure all such nested classes have unique names!
 
***********************************************************************************
 
Gordon, Thanks for the solution. It did work :) I have also tried the below method previously

basetrans trans = basetrans::type_id::create("trans");
$display ("Full_NAME=%0s", trans.get_full_name());
 
This was to get the hierarchical path of the transaction item. It was giving the result "env.seqr_4.seq_4.trans" and in the test, I had done the following

basetrans::type_id::set_inst_override(errtrans::get_type(), env.seqr_4.seq_4.* );
 
But, it was not working. Now that after adding context when creating
transaction item as given below, it is working

basetrans trans = basetrans::type_id::create("trans", , get_full_name());
Why is it required to specify context while creating transaction item?
 

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.