并不像正常的sequencer那样,将sequence item 通过sequencer port传递给driver。Virtual sequencer 通过一个指向subsequencer目标的句柄来指定sequence。这里的subsequencer就是和driver相连接的真实sequencer。所谓的virtual 就是指真正的sequence并不是在Virtual sequencer里产生和传递的。一个virtual sequencer 可以通过它的subsequencer产生许多种不同类型的tranction。
例1是virtual sequencer的典型结构,设定的名字是vsequencer。Virtual sequencer派生自UVM_sequencer,而不是uvm_virtual_sequencer(当然,并没有这个类)。virtual sequencer 与其他普通的sequencer最显著的区别就在于,virtual sequencer 并没有指定具体的tranction类型,因为virtual sequencer会执行多种类型的tranction。这里派生时未指定参数,意味着virtual sequencer会使用uvm_sequence_item的默认参数值。
上图,virtual sequencer声明了两个自sequencer句柄,分别是ahb_seq 和eth_sqr。这两个subsequencer将会在end_of_elaboration_phase()这一阶段被赋值。上述代码并没有采取UVM testbench中的大多数组件间常有的连接方式——TLM connect(),这里在环境中使用了配置数据的方式对其进行指定,这样virtual sequencer会在配置数据库中抽取相应的sequencer并赋给virtual sequencer 中声明好的句柄。真实的subsequencer会在build phase中创建。因此,这些subsequencer 句柄只能在connect_phase中被放入配置数据库。这样,virtual sequencer就不得不在下一个阶段重新检索他们,即 end_of_elaboration_phase()阶段。
从这里可以看出来,vsequencer只是一个容器,存放指向subsequencer的句柄以及一些其他配置参数。Virtual sequence假定virtual sequencer在virtual sequence在run phase阶段之前就已被合理的配置过了。他们可以在virtual sequencer中通过p_sequencer句柄访问配置参数。
什么是M-sequencer句柄呢?
所有的sequence都要在sequencer中启动:如tr_seq.start(env.vsqr)。当sequence启动的时候,m_sequencer 句柄就指向了env.vsqr。 m_sequencer 就是这样一个指向执行当前sequence的sequencer句柄。
什么是P-sequencer句柄呢?
UVM新手常有两个问题:
P_sequencer是什么呢?P-sequencer 与M-sequencer有什么区别?
所有的sequence 都有一个m_sequencer 句柄,但是m_squencer变量是个内部实现变量,而且由于参数类型的原型,通过这一句柄通常不能直接调用sequencer里的变量。任何以m_开的变量和方法也都是如此。
这时候为了方便,就使用了P_seuencer。但是任意sequence 并不会自动凭空就有p_sequencer。P_seuencer没有被自动声明,但是可以使用`uvm_declare_p_sequencer宏声明。当调用这一宏时,在virtual sequence 开启时,P_seuencer就会被自动声明、赋值,并正确的指向正在执行这一virtual sequence的virtual sequencer。
`uvm_declare_p_sequencer宏实际上完成了这两步。
- 声明了一个sequencer类型的句柄p_sequencer
- 这个宏将m_sequencer句柄转化为p_sequencer 类型的句柄。
具体对于`uvm_declare_p_sequencer宏源代码的解析,可参见原文。
所有的virtual sequence 都需要能访问定义于virtual sequencer中的subsequencer的句柄。于是virtual sequence需要使用`uvm_declare_p_sequencer 宏,由于每一个virtual sequence都需要执行这些步骤,所以我们推荐将这部分代码放入一个virtual sequence base class(vseq_base)中,然后基于此base class(vseq_base)派生出所有的virtual sequence。
在展示代码前,这里融合上文所讲例1,给出一个使用virtual sequencer机制的testbench框架图。
vseq_base 示例
为了更方便的管理sequence的公共方法,我们可以定义一个vseq_base。对应于example 1 的sequencer示例, vseq_base 具体代码如下。
本例中, vseq_base类利用p_sequencer 把virtual sequencer (p_sequencer)中的两个subsequencer的句柄拷贝到本地并赋给ahb_sqr 和eth_sqr.
创建virtual sequence
一旦virtual sequence 基类创建完成。我们就可以直接基于此基类派生创建virtual sequence了。如下例3和例4的两个virtual sequence示例。
例3的virtual sequence 使用了`uvm_do macros方法产生sequence,这里先产生了一个AHB packet sequence, 然后产生了两个Ethernet packet sequence, 最后产生了一个AHB packet。
Virtual sequence 就是以这样一种方法,调控sequence的序列顺序的。
例4的virtual sequence 使用了start方法产生sequence,并在此前进行了随机化。
virtual sequence 调用的sequence
Virtual sequence的另一个很重要的特点是,对于已经存在的sequence,它可以无需更改,就直接执行。比如用户创建了一个sequence库,就可以直接在不同模间块进行使用。
下图例5的AHB packet,这是一个"pseudo-AHB packet"。
如下所示,是一个AHB sequence 代码。这个简单的AHB sequence会随机的产生2-5个AHB packet。如上例3和例4的的virtual sequence将会根据这里的sequence定义随机发送AHB packet。
开启virtual sequence
一般来讲,virtual sequence会使用start方法启动。`uvm_do_on 宏是不能在test组建中直接调用的,`uvm_do_on 宏只能在派生的sequence 中调用,`uvm_do_on所需的方法 create_item(), start_item() 和finish_item()都不能在uvm_test 以及其他UVM component 中调用。
常见的好方法是,创建一个test_base 类,在其中声明一些公用的方法。然后在其派生的test类启动sequence
在派生的类中定义了run_phase,在run_phase 中创建一个virtual sequencer,并调用raise_objection() 和drop_objection()方法,在其中使用start()方法开启virtual sequence。
The environment sets the handles in the virtual sequencer
在environment 传递句柄给virtual sequencer
下图代码示例了一个典型的environment结构。这里实例化了一个virtual sequencer v_sqr, 并将两个sequencer(AHB agent 和 ETH agent 的sequencer)set到配置database。在我们一开始的时候,我们讲“如何实现virtual sequencer”的时候讲,virtual sequencer句柄在connect phase 中被存放到virtual sequencer中,并在end_of_elaboration() phase中重新检索就是这个意思。
本文叙述了一个简单的使用virtual sequencer机制的验证环境的搭建,对于UVM新手弄懂他们如何工作是很有参考意义的,对于源代码及原文更详细的描述,请参阅<<Using UVM Virtual Sequencers & Virtual Sequences>>