Welcome ! This website will help YOU (recent graduates/professionals) learn verification languages like SystemVerilog and UVM. Register for free and access more content !

User defined sequences should be derived from uvm_sequence, which has many methods to control the execution, runtime phasing, and other controls. One of them is the start() task which will execute the sequence, and return upon completion. This is just another way of running a sequence by the sequencer. Let's take a quick look at the start( ) method.

 
virtual task start ( uvm_sequencer_base   sequencer,
                     uvm_sequence_base    parent_sequence = null,
                     int                  this_priority = -1,
                     bit                  call_pre_post = 1 );
 

Note that you have to always pass the handle to a sequencer which should execute this sequence, whereas the other arguments are optional. parent_sequence is often referred to the sequence from which the current one was called. this_priority specifies a priority for the sequence (by default it assumes priority of the parent sequence), and can be ignored for now. call_pre_post will call the pre_body() and post_body() of the current sequence. Here's an example of how the start() function has to be used, and what happens in the background.

 
seq.randomize (...); // optional
seq.start (m_sequencer, null, , 1);
 
// The following methods will be called in start()
seq.pre_start();            (task)       
seq.pre_body();             (task)  if call_pre_post == 1
   parent_seq.pre_do()      (task)   if parent_seq != null
   parent_seq.mid_do(this)  (func)   if parent_seq != null
seq.body()                  (task)   your code
   parent_seq.post_do(this) (func)   if parent_seq != null
seq.post_body()             (task)   if call_pre_post == 1
sub_seq.post_start()        (task)
 
sequence flow

Simple sequence flow

To understand the sequence flow better, let us construct a simple sequence with a print statement in each of the above mentioned methods. First we'll try to understand how call_pre_post argument affects the output.

 
// Let's just declare a base sequence from which we can have a child sequence
// This will help to prove execution order of pre_do, mid_do and post_do tasks
class base_seq extends uvm_sequence;
 
  // Factory registration and new function is assumed to be written next
  ...
 
  // For every method during the body() execution flow, we'll simply add a display statement to track 
  // how each method in this sequence is getting executed
  virtual task pre_body();
    `uvm_info (get_type_name(), "pre_body()", UVM_LOW)
  endtask
 
  virtual task pre_do(bit is_item);
    `uvm_info (get_type_name(), "pre_do()", UVM_LOW)
  endtask
 
  virtual function void mid_do(uvm_sequence_item this_item);
    `uvm_info (get_type_name(), "mid_do()", UVM_LOW)
  endfunction
 
  virtual task body();
    `uvm_info (get_type_name(), "body()", UVM_LOW)
  endtask
 
  virtual function void post_do(uvm_sequence_item this_item);
    `uvm_info (get_type_name(), "post_do()", UVM_LOW)
  endfunction
 
  virtual task post_body();
    `uvm_info (get_type_name(), "post_body()", UVM_LOW)
  endtask
endclass
 

Within our test case, we'll call the start method of our sequence base_seq. Note that the default value of call_pre_post argument of the start method is 1 and hence the pre_body and post_body tasks of that sequence will be called.

 
// Define a base test that will launch our base sequence
class base_test extends uvm_test;
  ...
 
  // Instantiate the base_seq and start it on default sequencer
  virtual task run_phase (uvm_phase phase);
    base_seq bs = base_seq::type_id::create ("bs", this);
    bs.start (null);     // Default value of call_pre_post is 1
  endtask
endclass
 

As expected, the sequence executes the pre_body and post_body tasks in addition to the body method.

Simulation Log
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO ./tb/tb_top.sv(19) @ 0: reporter@@bs [base_seq] pre_body()
UVM_INFO ./tb/tb_top.sv(31) @ 0: reporter@@bs [base_seq] body()
UVM_INFO ./tb/tb_top.sv(39) @ 0: reporter@@bs [base_seq] post_body()

--- UVM Report catcher Summary ---

Now, let's supply 0 to call_pre_post argument and see that pre_body and post_body methods are not executed.

 
class base_test extends uvm_test;
  ...
 
  // Call the same sequence with call_pre_post argument set to 0
  // This will show the difference in result compared to previous example
  virtual task run_phase (uvm_phase phase);
    base_seq bs = base_seq::type_id::create ("bs", this);
    bs.start (null, null, 0, 0);  // call_pre_post is given 0
  endtask
endclass  
 
Simulation Log
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO ./tb/tb_top.sv(31) @ 0: reporter@@bs [base_seq] body()

--- UVM Report catcher Summary ---

Takeaway: if call_pre_post is 1, then pre_body and post_body methods of the started sequence will be executed.

Inherited sequence flow

The second argument to start method is parent which might cause a confusion regarding the term parent used in inheritance versus the parent sequence that starts the main sequence. To try out an example, we'll create a child sequence of base_seq with a print statement in each of its methods and spawn that from the test case.

 
// The child sequence will have its own pre_body task to see pre_body() method of which parent is called
class child1_seq extends base_seq;
 
  // Again, to track the message lets just print this into the log
  virtual task pre_body();
    `uvm_info (get_type_name(), "pre_body()", UVM_LOW)
  endtask
 
  // Definition of all other methods like base class should come here
 
endclass
 
class base_test extends uvm_test;
  ...
 
  // Start the child sequence with the default value of call_pre_post
  virtual task run_phase (uvm_phase phase);
    child1_seq cs = child1_seq::type_id::create ("cs", this);
    cs.start (null);     // Default value of call_pre_post is 1
  endtask
endclass  
 

In this case also, we get a similar result as before where pre_body and post_body methods are invoked because of the default value of call_pre_post argument in the start method. So it is clear that parent argument simply specifies the parent sequence from where the main sequence is started.

Simulation Log
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO ./tb/tb_top.sv(19) @ 0: reporter@@bs [base_seq] pre_body()
UVM_INFO ./tb/tb_top.sv(31) @ 0: reporter@@bs [base_seq] body()
UVM_INFO ./tb/tb_top.sv(39) @ 0: reporter@@bs [base_seq] post_body()

--- UVM Report catcher Summary ---

Spawned sequence flow

Here, we'll start another sequence called child2_seq from the body method in child1_seq with rest of the code being the same. This example will demonstrate how the parent argument in start method can be used.

 
class child2_seq extends base_seq;
  ...
  virtual task pre_body();
    `uvm_info (get_type_name(), "pre_body()", UVM_LOW)
  endtask
 
  // Definition of all other methods like base class should come here
endclass
 
class child1_seq extends base_seq;
  ...
 
  virtual task body();
    child2_seq cs = child2_seq::type_id::create ("cs");
    cs.start (null);   // parent arg is by default null
  endtask
  ...
endclass
 

It can be seen that child2_seq also executed its own methods after which child1_seq execution is resumed.

Simulation Log
UVM_INFO @ 0: reporter [RNTST] Running test child1_test...                                                                                                                  
UVM_INFO ./tb/tb_top.sv(52) @ 0: reporter@@cs [child1_seq] pre_body()                                                                                                       
UVM_INFO ./tb/tb_top.sv(65) @ 0: reporter@@cs [child1_seq] body()                                                                                                           
UVM_INFO ./tb/tb_top.sv(87) @ 0: reporter@@cs2 [child2_seq] pre_body()
UVM_INFO ./tb/tb_top.sv(99) @ 0: reporter@@cs2 [child2_seq] body()                                                                   
UVM_INFO ./tb/tb_top.sv(107) @ 0: reporter@@cs2 [child2_seq] post_body()
UVM_INFO ./tb/tb_top.sv(76) @ 0: reporter@@cs [child1_seq] post_body()                                                                                                      

--- UVM Report catcher Summary ---

Now we'll supply the pointer to child1_seq as an argument to the parent of the start method in child2_seq.

 
class child1_seq extends base_seq;
  ...
 
  virtual task body();
    child2_seq cs = child2_seq::type_id::create ("cs");
    cs.start (null, this);     // Give handle of current seq as parent to child2
  endtask
  ...
endclass
 

Now it can be seen that pre_do, mid_do and post_do methods of the parent sequence child1_seq has been called.

Simulation Log
UVM_INFO @ 0: reporter [RNTST] Running test child1_test...                                                                                                                  
UVM_INFO ./tb/tb_top.sv(52) @ 0: reporter@@cs [child1_seq] pre_body()                                                                                                       
UVM_INFO ./tb/tb_top.sv(65) @ 0: reporter@@cs [child1_seq] body()                                                                                                           
UVM_INFO ./tb/tb_top.sv(87) @ 0: reporter@@cs.cs2 [child2_seq] pre_body()                                                                                                   
UVM_INFO ./tb/tb_top.sv(56) @ 0: reporter@@cs [child1_seq] pre_do()                                                                                                         
UVM_INFO ./tb/tb_top.sv(60) @ 0: reporter@@cs [child1_seq] mid_do()                                                                                                        
UVM_INFO ./tb/tb_top.sv(99) @ 0: reporter@@cs.cs2 [child2_seq] body()                                                                                                       
UVM_INFO ./tb/tb_top.sv(72) @ 0: reporter@@cs [child1_seq] post_do()                                                                                                        
UVM_INFO ./tb/tb_top.sv(107) @ 0: reporter@@cs.cs2 [child2_seq] post_body()                                                                                                 
UVM_INFO ./tb/tb_top.sv(76) @ 0: reporter@@cs [child1_seq] post_body()                                                                                                      

--- UVM Report catcher Summary ---

Was this article helpful ?

We use cookies to personalize content and ads, to provide social media features and to analyze our traffic. You consent to our cookies if you continue to use our website. To find out more about the cookies we use and how to delete them, see our privacy policy.

  I accept cookies from this site.
Agree
EU Cookie Directive plugin by www.channeldigital.co.uk