Typical pattern for sequence body does 3 things:

  • Create object
  • Configure and randomize Object
  • Send Object
    req = req::type_id::create("req");

    start_item(req);

    // Do something here with req
    
    finish_item(req);

UVM provide two macros to do less typing… and confuse everyone (always bonus for UVM people). these macros are uvm_create and uvm_send

uvm_create Link to heading

Starting with uvm_create which calls uvm_create_on


	`uvm_create()

     // Do something here with req

	`uvm_send(req)
`define uvm_create(SEQ_OR_ITEM) \
  `uvm_create_on(SEQ_OR_ITEM, m_sequencer)

uvm_create uses uvm_create_on macro

`define uvm_create_on(SEQ_OR_ITEM, SEQR) \
  begin \
  uvm_object_wrapper w_; \
  w_ = SEQ_OR_ITEM.get_type(); \
  $cast(SEQ_OR_ITEM , create_item(w_, SEQR, `"SEQ_OR_ITEM`"));\
  end

create_item just calls the factory to create object of this sequence_item.

  protected function uvm_sequence_item create_item(uvm_object_wrapper type_var, 
                                                   uvm_sequencer_base l_sequencer, string name);

    uvm_factory f_ = uvm_factory::get();
    $cast(create_item,  f_.create_object_by_type( type_var, this.get_full_name(), name ));

    create_item.set_item_context(this, l_sequencer);
  endfunction

uvm_send Link to heading

Next uvm_send which uses uvm_send_pri macro

`define uvm_send(SEQ_OR_ITEM) \
  `uvm_send_pri(SEQ_OR_ITEM, -1)

uvm_send_pri expands to start_item and finish_item which is expected here.
but added bonus, uvm_send_pri detects if this is a sequence_item or sub-sequence. if it’s sub-sequence, it calls start instead.

`define uvm_send_pri(SEQ_OR_ITEM, PRIORITY) \
  begin \
  uvm_sequence_base __seq; \
  if (!$cast(__seq,SEQ_OR_ITEM)) begin \
     start_item(SEQ_OR_ITEM, PRIORITY);\
     finish_item(SEQ_OR_ITEM, PRIORITY);\
  end \
  else __seq.start(__seq.get_sequencer(), this, PRIORITY, 0);\
  end