在之前的文章中,我们看了TLM 1类的概述。 本文将为您提供一些使用TLM 1类的示例代码。
components
我们创建了以下组件来演示不同类型的TLM 1接口。 jelly_bean_sequencer(最左边的组件)创建jelly_bean_transaction的一个对象,名为jb_req。 jb_req通过几个TLM 1接口一直传送到右边(jelly_bean_transporter)。 jelly_bean_transporter评估jb_req的风格,并返回另一个名为jb_rsp(jelly-bean response)的带有更新后的taste属性的jelly_bean_transaction。 jb_rsp最后被传回给jelly_bean_subscriber。 虽然这个例子是tb中通常不这么用,但是它会向你展示各种TLM 1接口。
TLM 1示例连接
jelly_bean_sequencer
jelly_bean_sequencer是专门用于jelly_bean_transaction的uvm_sequencer。
typedef uvm_sequencer#(jelly_bean_transaction) jelly_bean_sequencer;
jelly_bean_put_driver
jelly_bean_put_driver是一个uvm_driver,这意味着它有一个seq_item_port。第4行声明另一个端口(put_port)。 在run_phase中从seq_item_port(第19行)获取一个jb_req,然后将它放到put_port(第21行)。
class jelly_bean_put_driver extends uvm_driver#( jelly_bean_transaction ); `uvm_component_utils( jelly_bean_put_driver ) uvm_put_port#( jelly_bean_transaction ) put_port; function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new function void build_phase( uvm_phase phase ); super.build_phase( phase ); put_port = new( .name( "put_port" ), .parent( this ) ); endfunction: build_phase task run_phase( uvm_phase phase ); jelly_bean_transaction jb_req; forever begin seq_item_port.get_next_item( jb_req ); `uvm_info( get_type_name(), "[seq_item_port]-->{jb_req}-->[put_port]", UVM_NONE ) put_port.put( jb_req ); seq_item_port.item_done(); end endtask: run_phase endclass: jelly_bean_put_driver
jelly_bean_master
jelly_bean_master有一个uvm_get_port(get_port,第4行),一个uvm_master_port(master_port,第5和6行)和一个uvm_analysis_port(rsp_ap,第7行)。 在run_phase中从get_port(第25行)获得一个jb_req,然后将其放到master_port(第27行)。 jelly_bean_master等待jelly bean响应(jb_rsp,第29行),然后将其写入rsp_ap(第31行)。
class jelly_bean_master extends uvm_component; `uvm_component_utils( jelly_bean_master ) uvm_get_port#( jelly_bean_transaction ) get_port; uvm_master_port#( .REQ( jelly_bean_transaction ), .RSP( jelly_bean_transaction ) ) master_port; uvm_analysis_port#( jelly_bean_transaction ) rsp_ap; function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new function void build_phase( uvm_phase phase ); super.build_phase( phase ); get_port = new( .name( "get_port" ), .parent( this ) ); master_port = new( .name( "master_port" ), .parent( this ) ); rsp_ap = new( .name( "rsp_ap" ), .parent( this ) ); endfunction: build_phase task run_phase( uvm_phase phase ); jelly_bean_transaction jb_req; jelly_bean_transaction jb_rsp; forever begin get_port.get( jb_req ); `uvm_info( get_type_name(), "[get_port]-->{jb_req}-->[master_port]", UVM_NONE ) master_port.put( jb_req ); `uvm_info( get_type_name(), "{jb_rsp}< --[master_port]", UVM_NONE ) master_port.get( jb_rsp ); `uvm_info( get_type_name(), "{jb_rsp}-->[rsp_ap]", UVM_NONE ) rsp_ap.write( jb_rsp ); end endtask: run_phase endclass: jelly_bean_master
jelly_bean_slave
jelly_bean_slave有一个uvm_master_imp(master_export,第4到6行)和一个uvm_transport_port(trans_port,第7和8行)。 jelly_bean_slave也有两个队列; req_q存储jb_reqs,rsp_q存储jb_rsps。 jelly_bean_slave实现uvm_master_imp的访问方法;即put,try_put,can_put,get,try_get,can_get,peek,try_peek和can_peek(第34到81行)。 在run_phase中从req_q获得jb_req(如果可用),然后调用trans_port的传输(第28行)。
class jelly_bean_slave extends uvm_component; `uvm_component_utils( jelly_bean_slave ) uvm_master_imp#( .REQ( jelly_bean_transaction ), .RSP( jelly_bean_transaction ), .IMP( jelly_bean_slave ) ) master_export; uvm_transport_port#( .REQ( jelly_bean_transaction ), .RSP( jelly_bean_transaction ) ) trans_port; jelly_bean_transaction req_q[$]; jelly_bean_transaction rsp_q[$]; function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new function void build_phase( uvm_phase phase ); super.build_phase( phase ); master_export = new( "master_export", this ); trans_port = new( .name( "trans_port" ), .parent( this ) ); endfunction: build_phase task run_phase( uvm_phase phase ); jelly_bean_transaction jb_rsp; forever begin wait ( req_q.size() > 0 ); `uvm_info( get_type_name(), "(master_export)---{jb_req}-->[trans_port]", UVM_NONE ) trans_port.transport( req_q.pop_front(), jb_rsp ); `uvm_info( get_type_name(), "{jb_rsp}< --[trans_port]", UVM_NONE ) rsp_q.push_back( jb_rsp ); end endtask: run_phase virtual task put( input jelly_bean_transaction t ); req_q.push_back( t ); endtask: put virtual function bit try_put( input jelly_bean_transaction t ); req_q.push_back( t ); return 1; endfunction: try_put virtual function bit can_put(); return 1; endfunction: can_put virtual task get( output jelly_bean_transaction t ); wait ( rsp_q.size() > 0 ); t = rsp_q.pop_front(); endtask: get virtual function bit try_get( output jelly_bean_transaction t ); if ( rsp_q.size() > 0 ) begin t = rsp_q.pop_front(); return 1; end else begin return 0; end endfunction: try_get virtual function bit can_get(); return rsp_q.size() > 0; endfunction: can_get virtual task peek( output jelly_bean_transaction t ); wait ( rsp_q.size() > 0 ); t = rsp_q[0]; endtask: peek virtual function bit try_peek( output jelly_bean_transaction t ); if ( rsp_q.size() > 0 ) begin t = rsp_q[0]; return 1; end else begin return 0; end endfunction: try_peek virtual function bit can_peek(); return rsp_q.size() > 0; endfunction: can_peek endclass: jelly_bean_slave
jelly_bean_transporter
jelly_bean_transporter有一个uvm_transport_imp(trans_export,第4至6行)并实现其访问方法;即transport和nb_transport(第17至32行)。这些方法创建jelly bean响应(jb_rsp,第24行),评估jelly bean请求的风味并相应地更新jb_rsp的taste属性(第26至29行)。
class jelly_bean_transporter extends uvm_component; `uvm_component_utils( jelly_bean_transporter ) uvm_transport_imp#( .REQ( jelly_bean_transaction ), .RSP( jelly_bean_transaction ), .IMP( jelly_bean_transporter ) ) trans_export; function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new function void build_phase( uvm_phase phase ); super.build_phase( phase ); trans_export = new( "trans_export", this ); endfunction: build_phase virtual task transport( input jelly_bean_transaction jb_req, output jelly_bean_transaction jb_rsp ); assert( nb_transport( jb_req, jb_rsp ) ); endtask: transport virtual function bit nb_transport( input jelly_bean_transaction jb_req, output jelly_bean_transaction jb_rsp ); jb_rsp = jelly_bean_transaction::type_id::create( "jb_rsp" ); jb_rsp.copy( jb_req ); if ( jb_req.flavor == jelly_bean_transaction::CHOCOLATE && jb_req.sour ) jb_rsp.taste = jelly_bean_transaction::YUCKY; else jb_rsp.taste = jelly_bean_transaction::YUMMY; `uvm_info( get_type_name(), { "Returning:\n", jb_rsp.sprint() }, UVM_NONE ) return 1; endfunction: nb_transport endclass: jelly_bean_transporter
jelly_bean_subscriber
jelly_bean_subscriber是一个uvm_subscriber,这意味着它有一个analysis_export。 jelly_bean_subscriber实现了analysis_export的写入方法(第8至10行)。
class jelly_bean_subscriber extends uvm_subscriber#( jelly_bean_transaction ); `uvm_component_utils( jelly_bean_subscriber ) function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new function void write( jelly_bean_transaction t ); `uvm_info( get_type_name(), { "Received:\n", t.sprint() }, UVM_NONE ) endfunction: write endclass: jelly_bean_subscriber
jelly_bean_agent
jelly_bean_agent实例化所有组件并将它们连接在一起。
class jelly_bean_agent extends uvm_agent; `uvm_component_utils( jelly_bean_agent ) jelly_bean_sequencer jb_seqr; jelly_bean_put_driver jb_put_drvr; uvm_tlm_fifo#( jelly_bean_transaction ) jb_fifo; jelly_bean_master jb_master; jelly_bean_slave jb_slave; jelly_bean_transporter jb_trans; jelly_bean_subscriber jb_sub; function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new function void build_phase( uvm_phase phase ); super.build_phase( phase ); jb_seqr = jelly_bean_sequencer ::type_id::create( .name( "jb_seqr" ), .parent( this ) ); jb_put_drvr = jelly_bean_put_driver ::type_id::create( .name( "jb_put_drvr" ), .parent( this ) ); jb_fifo = new( .name( "jb_fifo" ), .parent( this ) ); jb_master = jelly_bean_master ::type_id::create( .name( "jb_master" ), .parent( this ) ); jb_slave = jelly_bean_slave ::type_id::create( .name( "jb_slave" ), .parent( this ) ); jb_trans = jelly_bean_transporter::type_id::create( .name( "jb_trans" ), .parent( this ) ); jb_sub = jelly_bean_subscriber ::type_id::create( .name( "jb_sub" ), .parent( this ) ); endfunction: build_phase function void connect_phase( uvm_phase phase ); super.connect_phase( phase ); jb_put_drvr.seq_item_port.connect( jb_seqr.seq_item_export ); jb_put_drvr. put_port.connect( jb_fifo.put_export ); jb_master. get_port.connect( jb_fifo.get_peek_export ); jb_master. master_port.connect( jb_slave.master_export ); jb_slave. trans_port.connect( jb_trans.trans_export ); jb_master. rsp_ap.connect( jb_sub.analysis_export ); endfunction: connect_phase endclass: jelly_bean_agent
Simulation
这是一个仿真输出的摘录。
# UVM_INFO ../src/tutorial_20.sv(118) @ 0: uvm_test_top.jb_env.jb_agent.jb_seqr@@jb_seq [one_jelly_bean_sequence] Generated: # UVM_INFO ../src/tutorial_20.sv(152) @ 0: uvm_test_top.jb_env.jb_agent.jb_put_drvr [jelly_bean_put_driver] [seq_item_port]-->{jb_req}-->[put_port] # UVM_INFO ../src/tutorial_20.sv(188) @ 0: uvm_test_top.jb_env.jb_agent.jb_master [jelly_bean_master] [get_port]-->{jb_req}-->[master_port] # UVM_INFO ../src/tutorial_20.sv(223) @ 0: uvm_test_top.jb_env.jb_agent.jb_slave [jelly_bean_slave] (master_export)---{jb_req}-->[trans_port] # UVM_INFO ../src/tutorial_20.sv(282) @ 0: uvm_test_top.jb_env.jb_agent.jb_trans [jelly_bean_transporter] Returning: # UVM_INFO ../src/tutorial_20.sv(225) @ 0: uvm_test_top.jb_env.jb_agent.jb_slave [jelly_bean_slave] {jb_rsp}< --[trans_port] # UVM_INFO ../src/tutorial_20.sv(190) @ 0: uvm_test_top.jb_env.jb_agent.jb_master [jelly_bean_master] {jb_rsp}<--[master_port] # UVM_INFO ../src/tutorial_20.sv(192) @ 0: uvm_test_top.jb_env.jb_agent.jb_master [jelly_bean_master] {jb_rsp}-->[rsp_ap] # UVM_INFO ../src/tutorial_20.sv(298) @ 0: uvm_test_top.jb_env.jb_agent.jb_sub [jelly_bean_subscriber] Received:我希望本教程能帮助你理解TLM 1接口。