首页 > 编程知识 正文

铁道通信与信息化技术专业,现代移动通信技术专业

时间:2023-05-04 06:50:21 阅读:225172 作者:803

文章目录 简介1.端口的使用2.单向通信3.双向通信4.多向通信5.通信管道1. TLM_FIFO2. Analysis Port3. Analysis TLM FIFO4. request & response 通信管道

简介

系统原型阶段和芯片验证阶段均使用了TLM通信方式。前者是为了更快地实现硬件原型之间的数据通信,后者是为了更快地实现验证组件之间的通信。

仿真速度是TLM对项目进度的最大贡献,同时TLM传输中的事务又可以保证足够大的信息量和准确性。

TLM并不是某种语言的产物,而是作为一种提高数据传输抽象级的标准存在的。

TLM是一种基于事务(Transaction)的通信方式,通常在高抽象级语言,例如SystemC、SV/UVM中作为模块间的通信方式。

TLM通信保证了 相邻组件之间的通信不再通过显式句柄引用,而是独立于组件的通信方式,为验证 组件的复用提供了很好地封闭性

基本概念

TLM通信需要两个通信的对象(分别称为initiator 和 target)。谁先发起通信请求,谁就属于initiator,而作为通信的响应方,称为target。按照Transaction的流向,可以将对象分为 producer 和 consumer。数据从哪里产生,它就属于producer,而数据流向了哪里,它就属于consumer。注意:transaction的流向不一定是从initiator流向target,也可能是target流向initiator。

initiator 与 target 的关系同 producer 与consumer的关系不是固定的 。

有了两个参与通信的对象后,用户需要将TLM通信方法在target一端中实现,以便于initiator将来作为发起方可以调用target的通信方法,实现数据传输。

最后需要将两个对象进行连接,需要在两个TLM对象中创建TLM端口,继而在更高层次中将这两个对象进行连接。

TLM通信步骤:

分辨出initiator 和 target ,producer 和 consumer;在 target 中实现TLM通信方法;在两个对象中创建TLM端口,initiator中创建port端口,target端创建沉静的羊端口;在更高层次对两个对象的端口进行连接。

分类:

从数据流向来看,传输方向分为单向和双向

单向传输:由initiator发起request transaction双向传输:由initiator发起request transaction,传送至target,继而target在消化了request transaction后,会发起responde transaction返回给initiator。

端口按照类型可以分为3种:

port:经常作为initiator的发起端,initiator凭借port才可以访问target的TLM通信方法;export:作为initiator和target中间层次的端口;沉静的羊:只能作为target接受request的末端,它无法作为中间层次的端口,所以沉静的羊到的连接无法再次延伸。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w7m65CAs-1623290831297)(C:UsersxrtAppDataRoamingTyporatypora-user-images1622704863388.png)]

1.端口的使用

就单向端口而言,声明port和export作为request发起方,参数只需要指定transaction类型参数,而声名沉静的羊作为request接收方,参数有2个,第一个指定指定transaction类型,第二个指定它所在的component类型。

就声明双向端口而言,指定参数需要考虑双向传输的因素,将传输类型transaction拆分为request transaction 和response transaction。
TLM端口连接的一般做法:

在initiator端例化port,在中间层例化export,在target端例化沉静的羊,在build_phase中创建;

多个port可以连接到同一个export或者沉静的羊;但是单个port或者export无法连接到多个沉静的羊上;

可以理解成多个initiator可以对同一个target发起request,但是同一个initiator无法连接多个target;
注:后文使用 Analysis Port或者Analysis TLM FIFO通信管道可以实现一端对多端。

port 可以连接port 、export 和 沉静的羊;export 可以连接 export 和沉静的羊 上;沉静的羊是数据传输的终点,无法扩展连接。

2.单向通信

单向通信是指由initiator 到target之间的数据流向是单一方向的,或者说initiator和target只能扮演producer和consumer中的一个角色。

声明port和export作为request发起方,参数只需要指定transaction类型参数,而声名沉静的羊作为request接收方,参数有2个,第一个指定指定transaction类型,第二个指定它所在的component类型。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ck0TC9FW-1623290831307)(C:UsersxrtAppDataRoamingTyporatypora-user-images1622706137470.png)]

阻塞端口的方法类型是task,这保证了可以实现事件等待和延时;非阻塞端口的方式为function类型,这确保调用可以立即返回。

blocking阻塞传输的方法:

put():initiator先生成数据T t ,同时将数据传送至targetget():initiator从target获取数据T t ,而target中的该数据T t 则应消耗peek():initiator从target获取数据T t ,而target中的该数据T t 还应该保留

nonblocking非阻塞函数为:

try_put()

can_put()

try_get()

can_get()

try_peek()

can_peek()

函数try_xxx可以发送和获取数据,如果成功,返回1,失败返回0;可以通过can_xxx先试探target是否可以接受数据,再通过try_xxx发送,提高数据发送的成功率。

3.双向通信

双向通信的initiator和target两端之间数据流向是双向的,即两端initiator和target同时twdlhproducer和consumer,而initiator作为request发起方,在发起request后,还会等待response返回。

双向端口按照通信握手方式可以分为:

transport 双向通信方式master和 slave 双向通信方式

transport 端口通过 transport() 方法,可以在同一方法调用过程中完成 REQ 和 REP的发出和返回。

master 和slave的通信方式必须分别通过put 、get 和peek()的调用,使用两个方法才完成一次握手信号

master端口和slave 端口的区别:当initiator 作为 master时,它会发送REQ至 target端,然后再从target端获取 RSP;当initiator使用slave端口时,它会先从target端获取REQ,然后将RSP送至target端。

4.多向通信

多向通信仍然是两个组件之间的的通信,而不是多个组件之间的通信。

多向通信是指,如果initiator与target之间的相同TLM端口数目超过一个的情况,在target端的解决方法。

UVM通过端口宏声明方式来解决这一问题,它解决的核心问题在于让不同端口对应不同的任务名,这样就不会造成方法名的冲突

注意:当在target中两个端口访问同一个资源时,要使用旗语控制资源访问。

//在端口后增加“-decl”`uvm_blocking_put_沉静的羊_decl(SFX)//SFX表示后缀名称`uvm_nonblocking_put_沉静的羊_decl(SFX)...-------------------------------------------------`uvm_blocking_put_沉静的羊_decl(_p1)//定义了两个独一无二的沉静的羊端口类型`uvm_blocking_put_沉静的羊_decl(_p2)class comp1 extends uvm_component; uvm_blocking_put_port#(itrans) bp_port1;//两个同名端口 uvm_blocking_put_port#(itrans) bp_port2; ... function void build_phase(uvm_phase phase); bp_port1 = new("bp_port1",this);//例化端口 bp_port2 = new("bp_port2",this); endfunction task run_phase(uvm_phase phase); itrans t1,t2; fork t1 = new("t1",this); t2 = new("t2",this); this.bp_port1.put(t1);//发送两个itrans this.bp_port2.put(t2); join endtaskendclassclass comp2 extends uvm_component; uvm_blocking_put_沉静的羊_p1#(itrans,comp2) bt_沉静的羊_p1;//根据宏定义了两个沉静的羊端口 uvm_blocking_put_沉静的羊_p2#(itrans,comp2) bt_沉静的羊_p2; itrans t_q[$]; semaphore key;//注意共享资源要做互斥保护 ... function void build_phase(uvm_phase phase); bt_沉静的羊_p1 = new("bt_沉静的羊_p1",this);//例化端口 bt_沉静的羊_p2 = new("bt_沉静的羊_p2",this); endfunction task put_p1(itrans t);//端口名增加了后缀,对应实现的put方法名也增加了后缀 key.get();//注意如果是非阻塞的通信,这里就要用try_get t_q.push_back(t); key.put();//相应的这里做try_put endtask task put_p2(itrans t);//实现两个不同名的put方法 key.get(); t_q.push_back(t); key.put(); endtaskendclassclass env extends uvm_env; comp1 c1; comp2 c2; function void build_phase(uvm_phase phase); super.build_phase(phase); c1 = comp1::type_id::create("c1",this); c2 = comp2::type_id::create("c2",this); endfunction function void connect_phase(uvm_phase phase); super.connect_phase(phase); c1.bp_port1.connect(c2.bt_沉静的羊_p1); c1.bp_port2.connect(c2.bt_沉静的羊_p2); endfunctionendclass

注意:

initiator端只管发送,并不关心在target端实现对应方法会有方法名冲突的问题;target端为了防止同名方法名冲突,先定义宏`uvm_blocking_put_沉静的羊_decl(SFX) ,这里SFX表示后缀名称,以此可以声明带后缀的端口和方法名,如上面代码中的uvm_blocking_put_沉静的羊_p1#(itrans,comp2) bt_沉静的羊_p1和 put_p1(itrans t)
通信管道
TLM通信的实现方式都是端到端的,同时在target一端需要实现传输方法,如put() 和get()等 5.通信管道

TLM通信的实现方式都是端到端的,同时在target一端需要实现传输方法,如put() 和get()等;
monitor、coverage collector等组件在传输数据时,会存在一端到多端的传输,如何解决?

1. TLM_FIFO

在一般TLM传输过程中,无论initiator给target发起一个transaction,还是initiator从target获取一个transaction,transaction最终都会流向consumer中。在consumer没有分析transaction之前,我们希望将transaction先存储到本地的FIFO中供稍后使用,这就可以使用uvm_tlm_fifo这个组件。

uvm_tlm_fifo类是一个新组件,继承与uvm_component类,而且已经预先内置了多个端口以及实现了多个对应方法供用户使用。

uvm_tlm_fifo是组件,例化时需要传入两个参数,一个记录在工厂的参数名,一个parent;

uvm_tlm_fifo的功能类似于mailbox,不同的地方在于uvm_tlm_fifo提供了各种端口供用户使用。推荐initiator端例化put_port或者get_peek_port,来匹配uvm_tlm_fifo的端口类型。

2. Analysis Port

可以实现一端对多端的需求,即数据是从同一个源的TLM端口发出到达不同的组件。

如果数据源端发生变化需要通知跟它关联的多个组件时,可以利用软件设计模式之一 观察者模式(广播模式,observer pattern)来实现。

observer pattern的核心在于:

第一,这是从一个initiator端到多个target端的方式第二,analysis port采用的是”push"模式,即从initiator端调用多个target端的write()函数实现数据传输。

连接方式:

agent一侧例化了uvm_analysis_沉静的羊后还需要实现write()函数;在顶层连接。顶层将initiator端的 uvm_analysis_port 与多个target端的 uvm_analysis_沉静的羊 进行连接;当initiator端调用write()函数时,实际上是采用轮询的方式将所有连接的target端内置的write()函数进行了调用。由于函数立即返回的特点,无论连接多少个target端,initiator端调用write()函数总是立即返回的,不同之前的单端口函数调用的是,即便没有target与之相连,调用write()函数也不会发生错误 3. Analysis TLM FIFO

uvm_tlm_analysis_fifo为用户提供了可以搭配uvm_analysis_port端口、uvm_analysis_沉静的羊端口和write()函数;

uvm_tlm_analysis_fifo类继承于uvm_tlm_fifo,这表明它本身具有面向单一TLM端口的数据缓存特性,而同时该类又有一个uvm_analysis_沉静的羊端口;

连接方式:

将initiator的analysis port连接到uvm_tlm_analysis_fifo 的 get_export 端口,这样数据可以从initiator发起,写到各个uvm_tlm_analysis_fifo的缓存中。将多个target的get_port连接到tlm_analysis_fifo的get_export,注意保持端口类型的匹配,这样从target一侧需要调用get()方法就可以得到先前存储在tlm_analysis_fifo中的数据。 4. request & response 通信管道

UVM提供了两种简单的通信管道,他们作为数据缓存区域,既有TLM端口从外侧接收request 和 response,同时也有TLM端口供外侧获取request和response。

uvm_tlm_req_rsp_channeluvm_tlm_transport_channel

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。