UVM中p_sequencer和m_sequencer的用法及其区别

在sequencer中存在如下成员变量:

文件:my_sequencer.sv
4 class my_sequencer extends uvm_sequencer #(my_transaction);
5 bit[47:0] dmac;
6 bit[47:0] smac;
…
12 virtual function void build_phase(uvm_phase phase);
13 super.build_phase(phase);
14 void'(uvm_config_db#(bit[47:0])::get(this, "", "dmac", dmac));
15 void'(uvm_config_db#(bit[47:0])::get(this, "", "smac", smac));
16 endfunction
17
18 `uvm_component_utils(my_sequencer)
19 endclass

在其build_phase中,使用config_db::get得到这两个成员变量的值。之后sequence在发送transaction时,必须将目的地址设置dmac,源地址设置为smac。现在的问题是,如何在sequence的body中得到这两个变量的值呢?
在介绍嵌套的sequence时,引入了m_sequencer这个属于每个sequence的成员变量,但是如果直接使用m_sequencer得到这两个变量的值:

virtual task body();
…
repeat (10) begin
`uvm_do_with(m_trans, {m_trans.dmac == m_sequencer.dmac;
                       m_trans.smac == m_sequencer.smac;})
end
…
endtask

如上写法会引起编译错误。其根源在于m_sequencer是uvm_sequencer_base(uvm_sequencer的基类)类型的,而不是my_sequencer类型的。m_sequencer的原型为:
protected uvm_sequencer_base m_sequencer;
但是由于case0_sequence在my_sequencer上启动,其中的m_sequencer本质上是my_sequencer类型的,所以可以在my_sequence中通过cast转换将m_sequencer转换成my_sequencer类型,并引用其中的dmac和smac:

virtual task body();
my_sequencer x_sequencer;
…
$cast(x_sequencer, m_sequencer);
repeat (10) begin
`uvm_do_with(m_trans, {m_trans.dmac == x_sequencer.dmac;
                       m_trans.smac == x_sequencer.smac;})
end
…
endtask

上述过程稍显麻烦。在实际的验证平台中,用到sequencer中成员变量的情况非常多。UVM考虑到这种情况,内建了一个宏:
uvm_declare_p_sequencer(SEQUENCER)。这个宏的本质是声明了一个SEQUENCER类型的成员变量,如在定义sequence时,使
用此宏声明sequencer的类型:

//my_case0.sv
3 class case0_sequence extends uvm_sequence #(my_transaction);
4 my_transaction m_trans;
5 `uvm_object_utils(case0_sequence)
6 `uvm_declare_p_sequencer(my_sequencer) //note
…
24 endclass

则相当于声明了如下的成员变量:

class case0_sequence extends uvm_sequence #(my_transaction);
my_sequencer p_sequencer;
…
endclass

UVM之后会自动将m_sequencer通过cast转换成p_sequencer。这个过程在pre_body()之前就完成了。因此在sequence中可以
直接使用成员变量p_sequencer来引用dmac和smac:

//my_case0.sv
3 class case0_sequence extends uvm_sequence #(my_transaction);
…
12 virtual task body();
…
15 repeat (10) begin
16 `uvm_do_with(m_trans, {m_trans.dmac == p_sequencer.dmac;
17                        m_trans.smac == p_sequencer.smac;})
18 end
…
22 endtask
23
24 endclass

sequence作为一个类,是可以从其中派生其他sequence的:

//my_case0.sv
4 class base_sequence extends uvm_sequence #(my_transaction);
5 `uvm_object_utils(base_sequence)
6 `uvm_declare_p_sequencer(my_sequencer)
7 function new(string name= "base_sequence");
8 super.new(name);
9 endfunction
10 //define some common function and task
11 endclass
12
13 class case0_sequence extends base_sequence;
…
31 endclass

由于在同一个项目中各sequence都是类似的,所以可以将很多公用的函数或者任务写在base sequence中,其他sequence都从此
sequence派生。
普通的sequence这样使用没有任何问题,但对于那些使用了uvm_declare_p_sequence声明p_sequencer的base sequence,在派生
的sequence中是否也要调用此宏声明p_sequencer?这个问题的答案是否定的,因为uvm_declare_p_sequence的实质是在base
sequence中声明了一个成员变量p_sequencer。当其他的sequence从其派生时,p_sequencer依然是新的sequence的成员变量,所以无
须再声明一次了。
当然了,如果再声明一次,系统也并不会报错:

class base_sequence extends uvm_sequence #(my_transaction);
`uvm_object_utils(base_sequence)
`uvm_declare_p_sequencer(my_sequencer)
…e
ndclass
class case0_sequence extends base_sequence;
`uvm_object_utils(case0_sequence)
`uvm_declare_p_sequencer(my_sequencer)
…
endclass

虽然这相当于连续声明了两个成员变量p_sequencer,但是由于这两个成员变量一个是属于父类的,一个是属于子类的,所以
并不会出错。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值