初识m_sequencer、p_sequencer和uvm_declare_p_sequencer宏

一、m_sequencer

1、什么是m_sequencer

m_sequencer是定义在uvm_sequencer_item中的,uvm_sequencer_base类型的句柄,也就是说

  • m_sequencer是uvm_sequencer_item的成员变量

  • m_sequencer是指向uvm_sequencer_base的句柄

  • 任何派生于uvm_sequencer_item的类都会拥有一个m_sequencer

m_sequencer源码如下:

   classuvm_sequence_itemextendsuvm_transaction;
       ...
    protecteduvm_sequencer_basem_sequencer;
       ...
   endclass

m_sequencer在类库中的关系如下图紫色箭头所示:

2、为什么要有m_sequencer

sequence属于object,sequencer属于component。

正常来说,sequence无法与sequencer进行交互,也不可能通过component的结构层次获得顶层配置及其他信息。因此需要一个能沟通sequence和sequencer的桥梁,m_sequencer就是这个桥梁。

3、怎么使用m_sequencer

通常调用uvm_do系列宏时,uvm能够自动根据传入的sequence或sequence_item调用对应的方法。使m_sequencer由指向uvm_sequencer_base,变为指向用户指定的sequencer,(例如类库中的your_sequencer),如下图蓝色虚线将变为紫色实线。

由此搭建了sequence和sequencer的桥梁,调用其他方法同理(不管是什么方法,没有改变m_sequencer指向给定的sequencer这一本质)。

因此使用者只需要调用所需方法,有关于m_sequencer的使用由uvm自动完成了。

值得注意的一点是用户指定的sequencer是uvm_sequencer_base的子类,对于m_sequencer而言,此时是父类句柄指向了子类对象,这也为下面的动态转换打下了基础。

二、p_sequencer

1、什么是p_sequencer

p_sequencer是由`uvm_decalre_p_sequencer宏,定义在用户指定的sequence(例如类库中的your_sequence)中的,用户指定的类型的句柄(例如类库中的your_sequencer),也就是说

  • p_sequencer是由uvm_decalre_p_sequencer宏产生的

  • p_sequencer是用户指定的sequence的成员变量(这里是your_sequence的成员变量,因为`uvm_decalre_p_sequencer宏是在your_sequence中使用的)

  • p_sequencer是指向用户指定的类型的句柄(这里是your_sequencer的成员变量)

p_sequencer源代码如下:

   `defineuvm_declare_p_sequencer(SEQUENCER)
     SEQUENCERp_sequencer; //SEQUENCER是由用户指定的类型
     virtualfunctionvoidm_set_p_sequencer();
       super.m_set_p_sequencer(); //父类的m_set_p_sequencer是空函数
       if(!$cast(p_sequencer, m_sequencer))
       `uvm_fatal("DCLPSQ", $sformatf("%m %s Error casting p_sequencer, please verify that this sequence/sequence item is intended to execute on this type of sequencer", get_full_name()))
     endfunction

可能到这里还是有些抽象,接下来我们进行一个更为形象的说明。

2、为什么需要p_sequencer

在sequence机制中,sequence就像是一个快递,它可以装入商品(sequence_itm),也可以装入另一个快递(sequence);sequencer就像是商家,他把快递交给物流公司(driver),物流公司再把快递交给用户(DUT)。

当有很多个快递时,物流公司怎么知道把哪个快递交给哪个用户呢,这就需要商家给快递上注明收货人和发货人的信息(your_sequencer中的dmac和smac等)。

也就是说your_sequence要访问your_sequencer中的成员变量dmac和smac,虽然这是your_sequence中的m_sequencer经过调用`uvm_do后已经指向了your_sequencer,但此时他的类型还是uvm_sequencer_base,而uvm_sequencer_base是your_sequencer的父类。父类句柄直接访问子类对象是不允许的。

因此我们需要将m_sequencer的类型转换成子类类型(也就是your_sequencer)。

首先我们在your_sequencer中声明了一个your_sequencer类型的句柄x_sequencer,再将m_sequencer动态转换成子类句柄,这样your_sequence就可以访问your_sequencer的成员变量了。

代码如下:

   classyour_sequenceextendsuvm_sequence#(your_transaction);
     your_trasactionyour_trans;
     `uvm_object_utils(your_squence)
     ...
     
     virtualtaskbody();
         your_sequencerx_sequencer;//声明x_sequencer
         ...
         $cast(x_sequencer,m_sequencer);//动态转换
         ...
     repeat(10)
         begin
         `uvm_do_with(m_trans,{your_trans.dmac==x_sequencer.dmac;
                               your_trans.smac==x_sequencer.smac;})//访问your_sequencer中的变量
         end
     ...
   endclass

如此一来,快递(your_sequence)上就有了一个标明了收货发货信息(dmac和smac)的快递面单,物流公司(driver)就可以按照快递单来派送了。

但是每次都需要通过声明x_sequencer,再动态转换就像人工手写快递面单一样繁琐,因此uvm将上述过程封装成立宏`uvm_declare_p_sequencer,以后就可以自动打印快递面单了

3、怎么使用p_sequencer

只需要在你需要的sequence中调用宏uvm_declare_p_sequencer(SEQUENCER) ,uvm将自动做以下事情:

  • 声明一个x_sequencer,指向SEQUENCER(这里your_sequencer)。

  • 将m_sequencer动态转换成子类句柄。

你所需要做的只是考虑需要把哪些信息打印到快递面单上了。

参考资料

  1. 《UVM实战 卷Ⅰ》 张强著

  1. 《芯片验证漫游指南——从系统理论到UVM的验证全视界》刘斌著

  1. 芯片验证面试必考题:m_sequencer与p_sequencer的区别是什么?https://zhuanlan.zhihu.com/p/436911218

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值