一、前言
在UVM验证平台中,有些组件之间需要进行数据通信,比如driver
需要从sequencer
获取事务对象、scoreboard
要从reference model
获取对应的参考值等等。UVM为这些连接的组件构建了一套专门的机制用于数据通信,即TLM机制。本章将主要讲述有关TLM机制的相关内容。
二、什么是UVM TLM
TLM 即 Transaction Level Modeling(事务级建模),在UVM测试平台中,存在着组件之间的相互通信,比如agent
中driver
需要从sequencer
那里获取事务对象以及返回响应、monitor
将检测到的事务发送给reference model
、monitor
将DUT
的输出发送给scoreboard
以及reference model
将期望值发给scoreboard
等等。TLM为这些需要通讯的组件之间建立专门的通信信道,使它们之间可以进行数据通信。
三、为什么要使用TLM
UVM的TLM机制有哪些好处?
TLM机制为各个需要通信的组件之间,建立专门的通信信道。这些通信信道之间互不干扰,各自独立,可以有效避免各个组件进行通信的时候出现混乱。
可以实现组件间通信的方法有很多种,但是使用不当会导致不可预期的结果。比如可以使用全局变量进行通信,但这些变量可能会在不适当的时候改变,后果将是灾难性的;再比如可以通过mailbox
、事件
或者旗语
等其他手段进行通信,但它们的共同缺点就是当出现多个的时候可能会出现混乱。UVM TLM机制可以有效地解决这个问题。
比如reference model
与master_agent
中的monitor
之间的通信,在这两者之间建立专门的通信信道,保证reference model
只能从master_agent
中的monitor
获取数据,而不会从slave_agent
中的monitor
获取数据。
四、UVM TLM原理
首先是端对端的情况,也就是一组端口只对应两个组件。为了方便起见,规定producer
是事务的产生方,也就是事务的来源;而consumer
是事务的接收方,也就是事务发送的目标。图中箭头的方向代表了事务的流向。
第一种传输的方法:需要在对应的组件中创建相应的端口,TLM的功能是通过端口实现。为producer
创建一个port
类型的端口,在consumer
中创建一个import
类型的端口。这里需要说明的是,在TLM机制中,拥有port
类型端口的组件是发起操作的主动方,拥有import
类型端口的组件是被动方。在这种方法当中,producer
是port
类型的端口,所以它是主动方。
在这种模式下,当producer
有事务进行传输的时候,需要调用put
任务。调用该任务之后,事务就传送到consumer
中去了。该put
任务是port
的一个成员任务,参数tx为需要传输任务的句柄。而事实上,port
调用的put
任务是在consumer
组件中定义的。当调用consumer
中port
的put
任务时,就相当于调用了consumer
中所定义的put
任务。put
任务需要验证工程师自己定义,以实现想要的功能。
由于这种模式下,事务是由事务的产生方主动发送的,所以称这种模式为put
模式或者叫发送模式。
而第二种模式,与第一种模式相反,这种模式将port
类型的端口定义在consumer
当中,将import
类型的端口定义在producer
当中。此时,consumer
是操作的主动方,它要主动发起操作从producer
获取事务。当producer
产生事务之后,它不会主动发送该事务给consumer
,而是等待consumer
发起get
操作后才会进行发送。get
操作是consumer
通过调用其port
端口的get
任务实现,与之前put
操作类似,port
的get
任务需要在producer
中完成,当consumer
调用port
的get
时,就相当于调用了producer
组件的get
任务。
在这种模式下,事务是由事务的接收方主动获取的,所以称这种模式为get
模式或者叫获取模式。
现在来分析以上两种模式,他们都是主动发起操作,不管对方是否准备好。比如在put
模式下,producer
在发送事务时,并不知道consumer
是否可以接受事务。同样的在get
模式下,当consumer
想要获取事务时,并不知道producer
当中是否有事务需要发送。
因此,就出现了第三种模式。在两个组件之间加一个FIFO
来实现数据缓冲,这样就解决了上面的问题。在这种模式下,producer
和consumer
均为操作的主动方,FIFO
为被动方。当producer
中有事务产生时,既可以使用put
操作将该事务放入FIFO
中进行缓存,而不必等待consumer
获取事务,所以consumer
不会阻塞producer
的事务发送。
另一方面,当consumer
需要事务时,就可以调用get
操作,将FIFO
中的事务取出。producer
中port
的put
函数以及consumer
中port
的get
函数均在FIFO
中实现。由于这种模式是用缓存的方式来实现的,所以称之为FIFO
模式。
上面这三种模式都是点对点的,但是在有些情况下,可能会出现一个组件需要将一个事务同时发送给其它多个组件的情况。比如monitor
可能不仅仅需要将事务发送给reference model
,也需要将事务发送给用于覆盖率收集的其它组件。在UVM的TLM机制中,也有对应的实现方法,一个组件可以同时给对应的多个组件发送事务,注意,这个发送过程是同时进行的,并且发送的事务是一样的,在这种模式下发起操作的主动方总是producer
,需要对它定义一个类型为analysis
的端口,而在接收方,需要定义对应的analysis_port
类型的端口,下面来看看事务是如何从producer
分发到各个consumer
中去的。
当producer
中需要有事务进行传输的时候,它会调用write
方法,将事务分发到各个consumer
中去。发起write
操作的方法是调用analysis_port
端口的write
任务,这个write
任务会依次调用各个consumer
中的write
任务,每个consumer中的write
任务都需要验证工程师自己完成,以实现想要的功能。
这种一对多的模式称为write
模式,从原理上来看这是一种广播的模式,需要使用analysis
类型的端口。