m_sequencer和p_sequencer的个人理解
- 1、是什么?
- 2、为什么?
- 3、怎么用?
1、是什么?
m_sequencer:
- 可以理解为member_sequencer,隐藏or局部sequencer,。
- 类型是
uvm_sequencer_base 类型,定义在uvm_sequence_item类中,注意:类型很重要。 - 可以理解为每个sequence中默认都有m_sequencer这一成员变量。
- m_sequencer 是一个指向执行当前sequence的sequencer句柄。
p_sequencer:
- 可以理解为parent_sequencer,父类sequencer
- 使用 `uvm_declare_p_sequencer(my_sequencer) 宏声明p_sequencer,宏本质是在当前sequence也就是case0_sequence中声明了一个成员变量p_sequencer。
- 类型为
my_sequencer ,定义在case0_sequence中。 - p_sequencer是my_sequencer的句柄
2、为什么?
使用《UVM实战》中的例子
定义一个my_sequencer,内含成员变量dmac和smac。
再定义一个case0_sequence,case0_sequence在my_sequencer上启动:case0_sequence.start(my_sequencer)
1 2 3 4 5 6 7 8 9 10 11 12 13 | class case0_sequence extends uvm_sequence #(my_transaction); my_trasaction m_trans; `uvm_object_utils(case0_squence) ... virtual task body(); ... repeat(10) begin ... //如何得到dmac和smac? end ... endclass |
问题: 如何在case0_sequence的body()任务中得到my_sequencer中的成员变量dmac和smac?
思考:
- 所有的sequence都要在sequencer中启动:如case0_sequence.start(my_sequencer),当sequence启动的时候,m_sequencer 句柄就指向了my_sequencer,若case0_sequence.start(my_sequencer1),则此时m_sequencer 句柄指向了my_sequencer1。
- sequence是从uvm_object拓展而来,它不能访问uvm_component组成的uvm层次结构的,如果非要访问uvm_component就要通过一个媒介,这个媒介就是sequencer。
- m_sequencer可作为媒介,用于从sequence中访问组件层次结构中的配置信息和其他资源。可以通过调用m_sequencer.get_full_name() 来获取sequencer的完整层次名称。
- 使用case0_sequence默认的m_sequencer这个媒介获取dmac和smac,代码如下,但是编译错误?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class case0_sequence extends uvm_sequence #(my_transaction); my_trasaction m_trans; `uvm_object_utils(case0_squence) ... virtual task body(); ... repeat(10) begin `uvm_do_with(m_trans,{m_trans.dmac==m_sequencer.dmac; m_trans.smac==m_sequencer.smac;}) end ... endclass |
- 原因是m_sequencer类型是
uvm_sequencer_base (uvm_sequencer的基类),而不是my_sequencer 类型。 - 解决问题的关键是:将case0_sequence 的m_sequencer类型从
uvm_sequencer_base 转换成my_sequencer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class case0_sequence extends uvm_sequence #(my_transaction); my_trasaction m_trans; `uvm_object_utils(case0_squence) ... 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 ... endclass |
不会报错,完美解决!
3、怎么用?
到这看起来没有p_sequencer什么事情,那p_sequencer是干啥的??
上诉的做法有点麻烦,UVM提供了强大的内建宏`uvm_declare_p_sequencer(SEQUENCER)来解决这个问题。呈上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class case0_sequence extends uvm_sequence #(my_transaction); my_trasaction m_trans; `uvm_object_utils(case0_squence) `uvm_declare_p_sequencer(my_sequencer) //使用宏定义my_sequencer ... virtual task body(); ... repeat(10) begin `uvm_do_with(m_trans,{m_trans.dmac==p_sequencer.dmac; m_trans.smac==p_sequencer.smac;}) end ... endclass |
是不是很眼熟?其实就是将x_sequencer换成了p_sequencer,UVM会自动将m_sequencer通过$cast() 转换成p_sequencer,在pre_body() 之前完成。这样使用是不是就简单了很多,等价代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class case0_sequence extends uvm_sequence #(my_transaction); my_trasaction m_trans; `uvm_object_utils(case0_squence) ... virtual task body(); my_sequencer p_sequencer; ... $cast(p_sequencer,m_sequencer); ... repeat(10) begin `uvm_do_with(m_trans,{m_trans.dmac==p_sequencer.dmac; m_trans.smac==p_sequencer.smac;}) end ... endclass |
`uvm_declare_p_sequencer(my_sequencer)宏干了两件事:
- 声明了一个sequencer类型的句柄p_sequencer
- 将m_sequencer句柄通过$cast(p_sequencer,m_sequencer)转化为p_sequencer 类型的句柄。
那么还有一个问题,p_sequencer为什么理解成parent sequencer?
这个问题我也没大整明白,p_sequencer是my_sequencer的句柄,可以理解为m_sequencer的父类是my_sequencer吗?
1 | $cast(p_sequencer,m_sequencer);//父类传子类用 $cast |
m_sequencer类型转换成p_sequencer类型,父类传给子类的时候需要用$cast() ,这样m_sequencer就是parent sequencer…正好相反?没整明白,求大神解答。