sequence of UVM learning notes

Posted by exasp on Sat, 04 Dec 2021 21:34:58 +0100

1. Why use sequence

The main function of sequence is to facilitate the generation of transactions for testing. It is unreasonable to directly generate a transaction in the driver during verification. The reasons include:

  1. The function of the driver is to convert the transaction into an excitation signal. If the function generating the transaction is placed in the driver, the functions of the driver will be too coupled and cause unnecessary problems.
  2. If a transaction is generated directly in the driver in one test, the driver code must be modified when other transactions are generated in another test, which is not convenient for code reuse.

Therefore, when building the verification platform, we will get used to generating transaction s in the sequence, mount the sequence in the sequencer, and connect the driver and the sequencer to complete the generation of incentives.

2. Start sequence

There are two ways to start a sequence: direct start and default sequence start.

  1. Direct start
my_sequence my_seq;
my_seq = my_sequence::type_id::create("my_seq");
my_seq.start(sequencer);
  1. default sequence
class case0_sequence extends uvm_sequence #(my_transaction);
   my_transaction m_trans;

   function  new(string name= "case0_sequence");
      super.new(name);
   endfunction 
   
   virtual task pre_body();
      `uvm_info("sequence0", "pre_body is called!!!", UVM_LOW)
   endtask
   
   virtual task post_body();
      `uvm_info("sequence0", "post_body is called!!!", UVM_LOW)
   endtask
   
   virtual task body();
      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      #100;
      `uvm_info("sequence0", "body is called!!!", UVM_LOW)
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
   endtask

   `uvm_object_utils(case0_sequence)
endclass

class my_case0 extends base_test;

   function new(string name = "my_case0", uvm_component parent = null);
      super.new(name,parent);
   endfunction 
   extern virtual function void build_phase(uvm_phase phase); 
   `uvm_component_utils(my_case0)
endclass


function void my_case0::build_phase(uvm_phase phase);
   case0_sequence cseq;
   super.build_phase(phase);

   cseq = new("cseq");
   uvm_config_db#(uvm_sequence_base)::set(this, 
                                           "env.i_agt.sqr.main_phase", 
                                           "default_sequence", 
                                           cseq);
endfunction

class my_case1 extends base_test;
  
   function new(string name = "my_case1", uvm_component parent = null);
      super.new(name,parent);
   endfunction 
   
   extern virtual function void build_phase(uvm_phase phase); 
   `uvm_component_utils(my_case1)
endclass

function void my_case1::build_phase(uvm_phase phase);
   super.build_phase(phase);

   uvm_config_db#(uvm_object_wrapper)::set(this, 
                                           "env.i_agt.sqr.main_phase", 
                                           "default_sequence", 
                                           case0_sequence::type_id::get());
endfunction

3. Arbitration of sequence

It is allowed to start multiple sequences on the same sequencer at the same time, as follows:

task my_case0::main_phase(uvm_phase phase);
   sequence0 seq0;
   sequence1 seq1;

   seq0 = new("seq0");
   seq0.starting_phase = phase;
   seq1 = new("seq1");
   seq1.starting_phase = phase;
   env.i_agt.sqr.set_arbitration(SEQ_ARB_STRICT_FIFO);
   fork
      seq0.start(env.i_agt.sqr);
      seq1.start(env.i_agt.sqr);
   join
endtask

How to schedule the order between two sequences depends on the priority of the sequence and the arbitration mode of the current platform.

  1. Priority of sequence
    Each sequence is doing uvm_do has a priority parameter. The priority parameter must be greater than or equal to - 1. The higher the value, the higher the priority. By default, the priority parameter is - 1.
    The priority of sequence can be changed by yourself. Using uvm_do_pri() or uvm_do_pri_with()
`uvm_do_pri(transaction, priority)
`uvm_do_pri_with(transaction, priority,constraint)
  1. Arbitration mode of sequence
Arbitration modedescribe
SEQ_ARB_FIFOBy default, the sequencer's arbitration algorithm will strictly follow the first in first out order without considering the priority
SEQ_ARB_WEIGHTEDWeighted arbitration
SEQ_ARB_RANDOMCompletely random selection
SEQ_ARB_STRICT_FIFOStrictly follow the priority. When there are multiple sequence s with the same priority, they are selected in the order of first in first out
SEQ_ARB_STRICT_RANDOMIt is strictly in accordance with the priority. When there are multiple sequence s with the same priority, it is randomly selected from the highest priority
SEQ_ARB_USERUsers can customize a new arbitration algorithm

Topics: uvm