UVM driver和UVM sequencer使用UVM sequence item port和export进行连接。本文将解释sequence item port如何工作。在Agent中,我们seq_item_port
将jelly-bean driver(jb_drvr
)sequence item port()连接到jelly-bean sequencer()的sequence item export(seq_item_export
),jb_seqr
如下所示:
jb_drvr.seq_item_port.connect ( jb_seqr.seq_item_export );
driver调用get_next_item()
以获取jelly-bean传输(jb_tx
),
seq_item_port.get_next_item ( jb_tx );
然后在最后调用item_done()
。
seq_item_port.item_done ();
我们将在这篇文章中看看上面的代码是如何工作的。与sequence item port有关的类图如下所示。UVM标准库类以粉色显示,专用于该jelly_bean_transaction
类型的UVM类以黄色显示。
与sequence item port相关的类图
Sequence Item Port
jelly-bean driver的seq_item_port
是用
jelly_bean_transaction
限定的
uvm_seq_item_pull_port类。
uvm_seq_item_pull_port
类定义在
src/tlm1/uvm_sqr_connections.svh文件中,并且有两个宏组成。
- `UVM_SEQ_PORT
- `UVM_SEQ_ITEM_PULL_IMP
以下伪代码显示了这些宏如何扩展。
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
正如你在上面看到的那样,get_next_item()
和item_done()
的工作都只是代表this.m_if
的工作,仅仅是调用this.m_if中的方法
(第39和47行)。但是什么this.m_if
?在回答这个问题之前,让我们看看连接的另一端。
Sequence Item Export
该seq_item_export是
jelly-bean sequencer是一个jelly_bean_transaction
限定的uvm_seq_item_pull_imp
类型的类。该uvm_seq_item_pull_imp
类也被定义的src/tlm1/uvm_sqr_connections.svh
,由两个宏:
- `UVM_IMP_COMMON
- `UVM_SEQ_ITEM_PULL_IMP
以下伪代码显示了这些宏如何扩展。
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
与uvm_seq_item_pull_port
类相似,uvm_seq_item_pull_imp
类拥有get_next_item()
和item_done()
方法,并将他们的工作委托给m_imp
。m_imp
就是 sequence item export所属的sequencer。
Connection
现在让我们连接sequence item port and the sequence item export。以下序列图显示了连接中涉及的步骤。
UVM driver实例化seq_item_port(步骤1),并且UVM sequencer实例化seq_item_export(步骤2)。
- 当seq_item_port.connect(jb_seqr.seq_item_export)被调用时,它seq_item_export被存储在称为m_provided_by(步骤3)的数组中,
- 在进入end_of_elaboration_phase之前,resolve_bindings()函数被调用。该函数遍历端口连接并将“implementation” 存储到称为m_imp_list(步骤4)的数组中。该函数检查实现的数量。如果它是1,则函数将实现存储为m_if(步骤5)。这是m_if序列项目端口委托其作业。如果实现的数量为0,seq_item_port则保持不连接。如果实现的数量超过1个,那就是错误。
- 当seq_item_port.get_next_item()被调用时,任务调用get_next_item()的seq_item_export,这反过来又调用uvm_sequencer 的 get_next_item()(步骤6和7)。
- 类似地,当seq_item_port.item_done()被调用时,函数调用seq_item_export的item_done(),这反过来又调用uvm_sequencer的item_done()(步骤8和9)。
我希望这篇文章能帮助你理解顺序项目端口的工作原理。