目录
通信管道
TLM通信的实现方式的共同点在于都是端对端的,同时target一端需实现传输方法,例如put()或者get()。
- 对于
monitor、coverage collector
等组件在传输数据时,会存在一端到多端的传输,如何解决这一问题? - 几个TLM组件和端口可帮助用户解决问题:
TLM FIFO、analysis port、analysis TLM FIFO、request & response
通信管道。
TLM FIFO
- 在一般TLM传输过程中,无论是initiator给target发起一个transaction,还是initiator从target获取一个transaction,transaction最终都会流向consumer中。consumer没有分析transaction时先将该对象存储到本地FIFO*稍后使用。
- 需要分别在两个组件中例化端口,同时在target中实现相应的传输方法。
- 多数情况下需要实现的传输方法都是相似的,方法的主要内容是为了实现一个数据缓存功能。
-
TLM FIFO uvm_tlm_fifo
类是一个新组件,它继承于uvm_component
类,而且已经预先内置了多个端口以及实现了多个对应方法。 -
uvm_tlm_fifo
的功能类似于mailbox,不同之处在于它提供各种端口可以使用,推荐在initiator端例化put_port或get_peek_port匹配uvm_tlm_fifo的端口类型。 - 如果例化了其它类型的端口,
uvm_tlm_fifo
还提供put、get、peek对应的端口:uvm_put_imp #(T,this_type) blocking_put_export
uvm_put_imp #(T,this_type) nonblocking_put_export
uvm_get_peek_imp #(T,this_type) blocking_get_export
uvm_get_peek_imp #(T,this_type) nonblocking_get_export
uvm_get_peek_imp #(T,this_type) get_export
uvm_get_peek_imp #(T,this_type) blocking_peek_export
uvm_get_peek_imp #(T,this_type) nonblocking_peek_export
uvm_get_peek_imp #(T,this_type) peek_export
uvm_get_peek_imp #(T,this_type) blocking_get_peek_export
uvm_get_peek_imp #(T,this_type) nonblocking_get_peek_export
Analysis Port
- 除了端对端的传输,在一些情况下还有多个组件会对同一个数据进行运算处理。
- 如果这个数据从同一个源的TLM端口发出到达不同的组件,这就要求该端口可以满足从一端到多端的需求。
- 如果数据源端发生变化需要通知跟它关联的多个组件时,可以利用软件设计模式的观察者模式来实现。
-
观察者模式的核心在于:
- 这是从一个initiator端到多个target端的方式;
-
analysis port
采取的是“push”模式,即从initiator端调用多个target端的write()
函数实现数据传输。
initiator.ap.connect(target1.aimp);
initiator.ap.connect(target2.aimp);
initiator.ap.connect(target3.aimp);
- 典型的
analysis port
类型端口的连接方式,类似其它TLM端口,按传输方法和端口方向组合可将analysis port分为uvm_analysis_port、uvm_analysis_export、uvm_analysis_imp
。 -
target一侧例化了uvm_analysis_imp后还需要实现
write()
函数。 - 在顶层可以将initiator端的
uvm_analysis_port
同多个target端的uvm_analysis_imp
进行连接。 - 在initiator端调用
write()
函数时,实际上它是通过循环的方式将所有连接的target端内置的write()
函数进行了调用。 - 由于函数立即返回的特点,无论连接多少个target端,initiator端调用write()函数可以立即返回。不同于之前单一端口函数调用的是,即使没有target与之相连,调用write()函数时也不会发生错误。
Analysis TLM FIFO
- 由于analysis端口提出实现了一端到多端的TLM数据传输,而新的数据存储组件类
uvm_tlm_analysis_fifo
提供可以搭配uvm_analysis_port
端口、uvm_analysis_imp
端口和write()
函数。 -
uvm_tlm_analysis_fifo类继承于uvm_tlm_fifo,这表明它本身具有面向单一TLM端口的数据缓存特性,同时该类又有一个
uvm_analysis_imp
端口analysis_export
并且实现了write()
函数:uvm_analysis_imp #(T, uvm_tlm_analysis_fifo #(T)) analysis_export;
。 - 基于initiator到多个target的连接方式,如果实现一端到多端的数据传输,可以插入多个
uvm_tlm_analysis_fifo
,连接方式如下:- 将initiator的
analysis_port
连接到tlm_analysis_fifo
的analysis_export
端口,这样数据可以从initiator发起,写入到各个tlm_analysis_fifo
的缓存中。 - 将多个target的
get_port
连接到tlm_analysis_fifo
的get_export
端口,注意保持端口类型的匹配,这样从target一侧只需要调用get()
方法就可以得到先前存储在tlm_analysis_fifo
中的数据。
- 将initiator的
initiator.ap.connect(tlm_analysis_fifo1.analysis_export);
target1.get_port.connect(tlm_analysis_fifo1.get_export);
initiator.ap.connect(tlm_analysis_fifo2.analysis_export);
target2.get_port.connect(tlm_analysis_fifo2.get_export);
initiator.ap.connect(tlm_analysis_fifo3.analysis_export);
target3.get_port.connect(tlm_analysis_fifo3.get_export);
Request & Response通信管道
- 双向通信端口transport,即通过在target端实现
transport()
方法可在一次传输中既发送request又可以接收response。 - UVM提供了两种简便的通信管道作为数据缓存区域,既有TLM端口从外侧接收request和response,同时也有TLM端口供外侧获取request和response。这两种TLM通信管道分别是
uvm_tlm_req_rsp_channel
和uvm_tlm_transport_channel
。 - 对于
uvm_tlm_req_rsp_channel
而言,它提供的端口首先是单一方向的,列出该类例化的端口:
uvm_put_export #(REQ) put_request_export;
uvm_put_export #(RSP) put_response_export;
uvm_get_peek_export #(RSP) get_peek_response_export;
uvm_get_peek_export #(REQ) get_peek_request_export;
uvm_analysis_port #(REQ) request_ap;
uvm_analysis_port #(RSP) response_ap;
uvm_master_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) master_export;
uvm_slave_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) slave_export;
- 有了这么多丰富的端口,用户可以使用成对的端口进行数据的存储和访问。需要注意的是,
uvm_tlm_req_rsp_channel
内部例化了两个mailbox分别用来存储request和response:protected uvm_tlm_fifo #(REQ) m_request_fifo;
protected uvm tlm_fifo #(RSP) m_response_fifo;
- 例如initiator端可以连接channel的
put_request_export
,target连接channel的get_peek_request_export
,同时target连接channel的put_response_export
,initiator连接channel的get_peek_response_export
端口。 - 通过这种对应的方式,使得initiator与target可以利用
uvm_tlm_req_rsp_channel
进行request与response的数据交换。
initiator.put_port.connect(req_rsp_channel.put_request_export);
target.get_peek_port.connect(req_rsp_channel.get_peek_request_export);
target.put_port.connect(req_rsp_channel.put_response_export);
initiator.get_peek_port.connect(req_rsp_channel.get_peek_response_export);
也可利用另一种连接方式:
initiator.master_port.connect(req_rsp_channel.master_export);
target.slave_port.connect(req_rsp_channel.slave_export);
- 通过这些方式可实现initiator与target之间*的request和response传输,而这两种连接方式仍需要分别调用两次方法才可完成request和response的传输。
- 在
uvm_tlm_req_rsp_channel
的基础上,UVM又添加了具备transport端口的管道组件uvm_tlm_transport_channel
类,它继承于uvm_tlm_req_rsp_channel
且例化了transport端口:uvm_transport_imp #(REQ, RSP, this_type) transport_export;
。 - 这个新的组件类型是针对一些无法流水化处理的request和response传输,例如initiator一端要求每次发送完request,必须等到response接收到以后才可以发送下一个request,这时
transport()
方法就可以满足这一需求。 - 如果将上面的传输方式进行修改,需要变化的是initiator端到
req_rsp_channel
的连接,应修改为:initiator.transport_port.connect(transport_channel.transport_export)
- transport_channel和target之间的连接,可以保留之前的单向传输连接方式。