UVM Tutorial for Candy Lovers – 11. Sequence Item Port

A UVM driver and a UVM sequencer are connected using a UVM sequence item port and an export. This post will explain how the sequence item port works. In Agent, we connected the sequence item port (seq_item_port) of the jelly-bean driver (jb_drvr) to the sequence item export (seq_item_export) of the jelly-bean sequencer (jb_seqr) like this:

jb_drvr.seq_item_port.connect( jb_seqr.seq_item_export );

The driver called get_next_item() to get a jelly-bean transaction (jb_tx),

seq_item_port.get_next_item( jb_tx );

and then called item_done() at the end.

seq_item_port.item_done();

We will look at how the above code works in detail in this post. The class diagram related to the sequence item port is shown below. UVM standard library classes are shown in pink, and the UVM classes specialized with the jelly_bean_transaction type are shown in yellow.

                                             Class Diagram Related to the Sequence Item Port

Sequence Item Port

The seq_item_port of the jelly-bean driver is an object of the uvm_seq_item_pull_port class specialized with the jelly_bean_transaction type. The uvm_seq_item_pull_port class is defined in src/tlm1/uvm_sqr_connections.svh and consists of two macros:

  • `UVM_SEQ_PORT
  • `UVM_SEQ_ITEM_PULL_IMP

The following pseudo code shows how these macros are expanded.

class uvm_seq_item_pull_port #( type REQ = jelly_bean_transaction, 
                                type RSP = REQ )
  extends uvm_port_base #( uvm_sqr_if_base #(REQ, RSP) );
 
   // `UVM_SEQ_PORT( `UVM_SEQ_ITEM_PULL_MASK, "uvm_seq_item_pull_port" )
   //  |              |
   //  |              V
   //  |           ( `UVM_SEQ_ITEM_GET_NEXT_ITEM_MASK      | 
   //  |             `UVM_SEQ_ITEM_TRY_NEXT_ITEM_MASK      |
   //  |             `UVM_SEQ_ITEM_ITEM_DONE_MASK          |
   //  |             `UVM_SEQ_ITEM_HAS_DO_AVAILABLE_MASK   |
   //  |             `UVM_SEQ_ITEM_WAIT_FOR_SEQUENCES_MASK |
   //  |             `UVM_SEQ_ITEM_PUT_RESPONSE_MASK       |
   //  |             `UVM_SEQ_ITEM_PUT_MASK                |
   //  |             `UVM_SEQ_ITEM_GET_MASK                |
   //  |             `UVM_SEQ_ITEM_PEEK_MASK ) = 9'h1FF
   //  V
 
   function new( string        name,
                 uvm_component parent,
                 int           min_size = 0,
                 int           max_size = 1 );
      super.new( name, parent, UVM_PORT, min_size, max_size );
      m_if_mask = 9'h1FF;
   endfunction // new
 
   //  |
   //  +--> `UVM_TLM_GET_TYPE_NAME( "uvm_seq_item_pull_port" )
 
   virtual function string get_type_name();
      return "uvm_seq_item_pull_port";
   endfunction // get_type_name
 
   // `UVM_SEQ_ITEM_PULL_IMP( this.m_if, 
   //  |                      jelly_bean_transaction, 
   //  |                      jelly_bean_transaction, t, t )
   //  V
 
   task get_next_item( output jelly_bean_transaction t );
      this.m_if.get_next_item( t );
   endtask // get_next_item
 
   task try_next_item( output jelly_bean_transaction t );
      this.m_if.try_next_item( t );
   endtask // try_next_item
 
   function void item_done( input jelly_bean_transaction t = null );
      this.m_if.item_done( t );
   endfunction // item_done
 
   task wait_for_sequences();
      this.m_if.wait_for_sequences();
   endtask // wait_for_sequences
 
   function bit has_do_available();
      return this.m_if.has_do_available();
   endfunction // has_do_available
 
   function void put_response( input jelly_bean_transaction t );
      this.m_if.put_response( t );
   endfunction // put_response
 
   task get( output jelly_bean_transaction t );
      this.m_if.get( t );
   endtask // get
 
   task peek( output jelly_bean_transaction t );
      this.m_if.peek( t );
   endtask // peek
 
   task put( input jelly_bean_transaction t );
      this.m_if.put( t );
   endtask // put
 
   // end of macro expansion
 
   bit print_enabled;
endclass // uvm_seq_item_pull_port

As you have seen above, both the get_next_item() and the item_done() simply delegates their job to this.m_if (lines 39 and 47). But what is this.m_if? Before answering this question, let’s look at the other side of the connection.

Sequence Item Export

The seq_item_export of the jelly-bean sequencer is an object of a uvm_seq_item_pull_imp class specialized with the jelly_bean_transaction type. The uvm_seq_item_pull_imp class is also defined in the src/tlm1/uvm_sqr_connections.svh and consists of two macros:

  • `UVM_IMP_COMMON
  • `UVM_SEQ_ITEM_PULL_IMP

The following pseudo code shows how these macros are expanded.

class uvm_seq_item_pull_imp 
  #( type REQ = jelly_bean_transaction,
     type RSP = REQ,
     type IMP = uvm_sequencer #( jelly_bean_transaction, 
                                 jelly_bean_transaction ) )
  extends uvm_port_base #( uvm_sqr_if_base #( REQ, RSP ) );
 
   // `UVM_IMP_COMMON( `UVM_SEQ_ITEM_PULL_MASK, "uvm_seq_item_pull_imp",
   //  |               uvm_sequencer #( jelly_bean_transaction,
   //  |                                jelly_bean_transaction ) )
   //  V
 
   local uvm_sequencer #( jelly_bean_transaction, 
                          jelly_bean_transaction ) m_imp;
 
   function new( string name, 
                 uvm_sequencer #( jelly_bean_transaction,
                                  jelly_bean_transaction ) imp );
      super.new( name, imp, UVM_IMPLEMENTATION, 1, 1 );
      m_imp     = imp;
      m_if_mask = 9'h1FF;
   endfunction // new
 
   //  |
   //  +--> `UVM_TLM_GET_TYPE_NAME( "uvm_seq_item_pull_imp" )
 
   virtual function string get_type_name();
      return "uvm_seq_item_pull_imp";
   endfunction // get_type_name
 
   // `UVM_SEQ_ITEM_PULL_IMP( m_imp, 
   //  |                      jelly_bean_transaction, jelly_bean_transaction,
   //  |                      t, t )
   //  V
 
   task get_next_item( output jelly_bean_transaction t );
      m_imp.get_next_item( t );
   endtask // get_next_item
 
   task try_next_item( output jelly_bean_transaction  t );
      m_imp.try_next_item( t );
   endtask // try_next_item
 
   function void item_done( input jelly_bean_transaction t = null );
      m_imp.item_done( t );
   endfunction // item_done
 
   task wait_for_sequences(); 
      m_imp.wait_for_sequences();
   endtask // wait_for_sequences
 
   function bit has_do_available();
      return m_imp.has_do_available();
   endfunction // has_do_available
 
   function void put_response( input jelly_bean_transaction t );
      m_imp.put_response( t );
   endfunction // put_response
 
   task get( output jelly_bean_transaction t );
      m_imp.get( t );
   endtask // get
 
   task peek( output jelly_bean_transaction t ); 
      m_imp.peek( t );
   endtask // peek
 
   task put( input jelly_bean_transaction t );
      m_imp.put( t );
   endtask // put
 
endclass // uvm_seq_item_pull_imp

Similar to the uvm_seq_item_pull_port class, the uvm_seq_item_pull_imp class has the get_next_item() and the item_done() methods, and they delegate their job to m_imp. The m_imp is the sequencer this sequence item export belongs to.

Connection

Now let’s connect the sequence item port and the sequence item export. The following sequence diagram shows the steps involved in the connection.

                                                                              Sequence Diagram

  • The UVM driver instantiates the seq_item_port (step 1), and the UVM sequencer instantiates the seq_item_export (step 2).
  • When seq_item_port.connect(jb_seqr.seq_item_export) is called, the seq_item_export is stored in the array called m_provided_by (step 3)
  • Just before entering end_of_elaboration_phaseresolve_bindings() function is called. This function traverses the port connection and stores “implementation” to the array called m_imp_list (step 4). The function checks the number of implementations. If it is 1, the function stores the implementation as m_if (step 5). This is the m_if the sequence item port delegated its jobs to. If the number of implementations is 0, the seq_item_port is left unconnected. If the number of implementations is more than 1, it is an error.
  • When the seq_item_port.get_next_item() is called, the task calls the get_next_item() of the seq_item_export, which in turn calls the get_next_item() of the uvm_sequencer (steps 6 and 7).
  • Similarly, when the seq_item_port.item_done() is called, the function calls the item_done() of the seq_item_export, which in turn calls the item_done() of the uvm_sequencer (steps 8 and 9).

I hope this post helped you to understand how the sequence item port works.

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页