Use of `uvm_do_* macros give the added advantage of inline constraints, but you lose the ability to control the invocation of pre_body()/post_body() methods of a sequence. It reduces the number of lines of code by randomizing the item, and reduces complexity by automatically calling the start() or start_item()/finish_item() based on whether the object given to the macro is a sequence or a sequence item.

uvm_sequence hierarchy

In How to use `uvm_do sequence macros ?, we learned that all `uvm_do_* macros ultimately call `uvm_do_on_pri_with code. So, let's see how that is structured within UVM to get better clarity behind the process.

`define uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS) \
  begin \
  uvm_sequence_base __seq; \
  `uvm_create_on(SEQ_OR_ITEM, SEQR) \
  if (!$cast(__seq,SEQ_OR_ITEM)) start_item(SEQ_OR_ITEM, PRIORITY);\
  if ((__seq == null || !__seq.do_not_randomize) && !SEQ_OR_ITEM.randomize() with CONSTRAINTS ) begin \
    `uvm_warning("RNDFLD", "Randomization failed in uvm_do_with action") \
  if (!$cast(__seq,SEQ_OR_ITEM)) finish_item(SEQ_OR_ITEM, PRIORITY); \
  else __seq.start(SEQR, this, PRIORITY, 0); \

Remember that uvm_sequence is a child or derivative of uvm_sequence_base which is inturn a child of uvm_sequence_item. If the object passed to the macro is a sequence item, then it creates the item and calls the start_item() method. Item will be randomized and finish_item() method will be called. If the object __seq is not a sequence item, then start() method of the sequence is called.

Note that pre_post field of the start() method is set to 0. That means the pre_body()/post_body() methods of a sequence will never be called when using `uvm_do_* macros. Execution flow is otherwise similar to what we saw when using start() task.

flow of sequences as shown in example


Let's take the same code we saw while using start(), and now call `uvm_do_pri_with instead. Below is the base_sequence from which three child sequences (seq1, seq2, seq3) are derived.

class base_sequence extends uvm_sequence #(my_data);
   `uvm_object_utils (base_sequence)
   `uvm_declare_p_sequencer (my_sequencer)
   function new (string name = "base_sequence"); (name);
   virtual function void mid_do (uvm_sequence_item this_item);
      `uvm_info (get_type_name (), "Executing mid_do", UVM_MEDIUM)
   virtual task pre_do (bit is_item);
      `uvm_info (get_type_name (), "Executing pre_do", UVM_MEDIUM)
   virtual function void post_do (uvm_sequence_item this_item);
      `uvm_info (get_type_name (), "Executing post_do", UVM_MEDIUM)
   virtual task body ();
      starting_phase.raise_objection (this);
      `uvm_info ("BASE_SEQ", $sformatf ("Starting body of %s", this.get_name()), UVM_MEDIUM)
      `uvm_info ("BASE_SEQ", $sformatf ("Sequence %s is over", this.get_name()), UVM_MEDIUM)
      starting_phase.drop_objection (this);

In seq1 below, notice that we have used `uvm_do_pri_with macro with empty constraints and no priority. We expect this to call the stat() method of seq2, and skip the pre_body( ) and post_body( ) tasks.

class seq1 extends base_sequence;
   `uvm_object_utils (seq1)
   seq2 m_seq2;
   virtual task pre_start ();
      `uvm_info (get_type_name (), "Executing pre_start()", UVM_MEDIUM)
   function new (string name = "seq1"); (name);
   virtual task body ();
      starting_phase.raise_objection (this);
      m_seq2 = seq2::type_id::create ("m_seq2");
      `uvm_info ("SEQ1", "Starting seq1", UVM_MEDIUM)
      `uvm_do_pri_with (m_seq2, ,{})
      `uvm_info ("SEQ1", "Ending seq1", UVM_MEDIUM)
      starting_phase.drop_objection (this);

In seq2, we kick off another sequence (seq3) using the same macro.

class seq2 extends base_sequence;
   `uvm_object_utils (seq2)
   seq3 m_seq3;
   function new (string name = "seq2"); (name);
   virtual task pre_body ();
      `uvm_info (get_type_name(), "Executing pre_body", UVM_MEDIUM)
   virtual task body ();
      m_seq3 = seq3::type_id::create ("m_seq3");
      `uvm_info ("SEQ2", "Starting seq2", UVM_MEDIUM)
      `uvm_do_pri_with (m_seq3, ,{})
      `uvm_info ("SEQ2", "Ending seq2", UVM_MEDIUM)
   virtual task post_body ();
      `uvm_info (get_type_name(), "Executing post_body", UVM_MEDIUM)

In our final sequence, we don't do anything.

class seq3 extends base_sequence;
   `uvm_object_utils (seq3)
   function new (string name = "seq3"); (name);
   virtual task pre_body ();
      `uvm_info (get_type_name(), "Executing pre_body", UVM_MEDIUM)
   virtual task body ();
      `uvm_info ("SEQ3", "Starting seq3", UVM_MEDIUM)
      `uvm_info ("SEQ3", "Ending seq3", UVM_MEDIUM)
   virtual task post_body ();
      `uvm_info (get_type_name(), "Executing post_body", UVM_MEDIUM)
   virtual task post_start ();
      `uvm_info (get_type_name (), "Executing post_start", UVM_MEDIUM)

The simulation results might look a bit fuzzy. The important thing to note is that the pre_do/mid_do methods are called before the body( ) task is called. Let's do a simple dry run.

- SEQ1 : pre_start()  
- go to the body() of SEQ1
- Display "[SEQ1] Starting seq1"
- Start SEQ2                                // there's nothing in pre_start() and pre_body() is not called
- Call parent's (SEQ1) pre_do
- Display "[seq1] Executing pre_do"
- Call parent's (SEQ1) mid_do
- Display "[seq1] Executing mid_do"
- Call body() of SEQ2 
- Display "[SEQ2] Starting seq2"
- Start SEQ3 
execution flow of a sequence using `uvm_do

Simulation Results

CDNS-UVM-1.1d (14.10-s013)
(C) 2007-2013 Mentor Graphics Corporation
(C) 2007-2013 Cadence Design Systems, Inc.
(C) 2006-2013 Synopsys, Inc.
(C) 2011-2013 Cypress Semiconductor Corp.
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO @ 0: reporter [UVMTOP] UVM testbench topology:
Name                     Type                    Size  Value
uvm_test_top             base_test               -     @2644
  m_top_env              my_env                  -     @214
    m_drv0               my_driver               -     @208
      rsp_port           uvm_analysis_port       -     @2843
      seq_item_port      uvm_seq_item_pull_port  -     @2792
    m_seqr0              my_sequencer            -     @2743
      rsp_export         uvm_analysis_export     -     @2933
      seq_item_export    uvm_seq_item_pull_imp   -     @3481
      arbitration_queue  array                   0     -
      lock_queue         array                   0     -
      num_last_reqs      integral                32    'd1
      num_last_rsps      integral                32    'd1

UVM_INFO ./tb/ @ 0: uvm_test_top.m_top_env.m_drv0 [my_driver] Applying initial reset
UVM_INFO ./tb/ @ 390000: uvm_test_top.m_top_env.m_drv0 [my_driver] DUT is now out of reset
UVM_INFO ./tb/ @ 390000: uvm_test_top.m_top_env.m_drv0 [my_driver] Waiting for data from sequencer
UVM_INFO ./tb/ @ 390000: uvm_test_top.m_top_env.m_seqr0@@seq1 [seq1] Executing pre_start()
UVM_INFO ./tb/ @ 390000: uvm_test_top.m_top_env.m_seqr0@@seq1 [SEQ1] Starting seq1
UVM_INFO ./tb/ @ 400000: uvm_test_top.m_top_env.m_seqr0@@seq1 [seq1] Executing pre_do
UVM_INFO ./tb/ @ 400000: uvm_test_top.m_top_env.m_seqr0@@seq1 [seq1] Executing mid_do
UVM_INFO ./tb/ @ 400000: uvm_test_top.m_top_env.m_seqr0@@seq1.m_seq2 [SEQ2] Starting seq2
UVM_INFO ./tb/ @ 410000: uvm_test_top.m_top_env.m_seqr0@@seq1.m_seq2 [seq2] Executing pre_do
UVM_INFO ./tb/ @ 410000: uvm_test_top.m_top_env.m_seqr0@@seq1.m_seq2 [seq2] Executing mid_do
UVM_INFO ./tb/ @ 410000: uvm_test_top.m_top_env.m_seqr0@@seq1.m_seq2.m_seq3 [SEQ3] Starting seq3
UVM_INFO ./tb/ @ 420000: uvm_test_top.m_top_env.m_seqr0@@seq1.m_seq2.m_seq3 [SEQ3] Ending seq3
UVM_INFO ./tb/ @ 420000: uvm_test_top.m_top_env.m_seqr0@@seq1.m_seq2 [seq2] Executing post_do
UVM_INFO ./tb/ @ 420000: uvm_test_top.m_top_env.m_seqr0@@seq1.m_seq2.m_seq3 [seq3] Executing post_start
UVM_INFO ./tb/ @ 420000: uvm_test_top.m_top_env.m_seqr0@@seq1.m_seq2 [SEQ2] Ending seq2
UVM_INFO ./tb/ @ 420000: uvm_test_top.m_top_env.m_seqr0@@seq1 [seq1] Executing post_do
UVM_INFO ./tb/ @ 420000: uvm_test_top.m_top_env.m_seqr0@@seq1 [SEQ1] Ending seq1
UVM_INFO ./tb/ @ 420000: uvm_test_top.m_top_env.m_drv0 [my_driver] Finished DUT simulation

--- UVM Report catcher Summary ---

Was this article helpful ?