现在我们来一步一步解析,如何构造virtual sequencer和virtual sequence以及他们背后的原理,先看一段uvm 源码:
uvm_do_on的源码如下:
// MACRO: `uvm_do_on
//
//| `uvm_do_on(SEQ_OR_ITEM, SEQR)
//
// This is the same as <`uvm_do> except that it also sets the parent sequence to
// the sequence in which the macro is invoked, and it sets the sequencer to the
// specified ~SEQR~ argument.
`define uvm_do_on(SEQ_OR_ITEM, SEQR) \
`uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, -1, {})
uvm_do_on_with的源码如下:
// MACRO: `uvm_do_on_pri_with
//
//| `uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS)
//
// This is the same as `uvm_do_pri_with except that it also sets the parent
// sequence to the sequence in which the macro is invoked, and it sets the
// sequencer to the specified ~SEQR~ argument.
`define uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS) \
begin \
uvm_sequence_base __seq; \
`uvm_create_on(SEQ_OR_ITEM, SEQR) \
if (!$cast(__seq,SEQ_OR_ITEM)) start_item(SEQ_OR_ITEM, PRIORITY);\
if ((__seq == null || !__seq.do_not_randomize) && !SEQ_OR_ITEM.randomize() with CONSTRAINTS ) begin \
`uvm_warning("RNDFLD", "Randomization failed in uvm_do_with action") \
end\
if (!$cast(__seq,SEQ_OR_ITEM)) finish_item(SEQ_OR_ITEM, PRIORITY); \
else __seq.start(SEQR, this, PRIORITY, 0); \
end
首先我们查看源码能发现uvm_do_on其实是套着uvm_do_on_pri_with源码的壳子,实际上我们仍然调用的是uvm_do_on_pri_with本质上没有任何区别,只是uvm_do_on 默认了优先级和constraints,
uvm_declare_p_sequencer(SEQUENCER)源码如下:
`define uvm_declare_p_sequencer(SEQUENCER) \
SEQUENCER p_sequencer;\
virtual function void m_set_p_sequencer();\
super.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
简单地分析一下源码,uvm_delcare_p_sequencer实际上就是传递一个SEQUENCER类型的sequencer,将 m_sequencer强制类型转换成p_sequencer也就是说SEQUENCER类型的sequencer。
前置需要说明展示的源码已经展示完,现在看virtual sequencer 和 virtual sequence的实现。
1,virtual sequencer 和virtual sequence的实现意义
virtual sequence:挂在到virtual sequencer上的虚假的sequence,是实现在真实sequencer上实现sequence的一种手段,用于控制sequence的执行顺序。
virtual sequencer:连接不同的sequencer,本身与在同一个sequencer上启动多个sequence是一样的,本身是一个连接器,将不同的sequencer句柄放在一起。
2,具体实现
1,virtual sequencer
class sample_virtual_sequencer extends uvm_sequencer;
`uvm_component_utils(sample_virtual_sequencer)
wr_sequencer wr_seqr;
rd_sequencer rd_seqr;
function new(string name="sample_virtual_sequencer",uvm_component parent=null);
super.new(name,parent);
endfunction
endclass : sample_virtual_sequencer
2,virtual sequence
class sample_virtual_sequence extends uvm_sequence;
`uvm_declare_p_sequencer(sample_virtual_seqencer)
`uvm_object_utils(sample_virtual_sequence);
wr_sequence wr_seq;
rd_sequence rd_seq;
virtual task body();
`uvm_do_on(wr_seq,p_sequencer.wr_seqr)
`uvm_do_on(rd_seq,p_sequencer.rd_seqr)
endtask
endclass sample_virtual_sequence
1,uvm_do_on 的使用:
关注上面的uvm_do_on的源码,uvm_do_on宏实际上时调用的uvm_do_on_pri_with这个宏:`define uvm_do_on_pri_with(SEQ_OR_ITEM,SEQR,PRIORITY,CONSTRAINTS)
第一个参数是sequence,第二个参数是sequencer,这里使用uvm_do_on的目的就是为了将seq 和 p_sequencer.seqr关联起来,将来是想要在 p_sequencer.seqr 上启动wr_seq,也就是env.agent0.seqr
2,uvm_do_on_with的使用:
uvm_do_on和uvm_do_on_with在源码上看都是同一套东西,无非是uvm_do_on_with可以是添加constraints,由于使用了uvm_declare_p_sequencer宏,可以通过p_sequencer来使用virtual_sequencer中的变量和参数:
`uvm_do_on_with(wr_seq,p_sequencer.wr_seqr,p_sequencer.xxx)
3,连接
class sample_testcase extends uvm_test;
sample_virtual_sequencer v_sequencer;
......
......
......
function void connect_phase(uvm_phase phase);
v_sequencer.wr_seqr = env.agent0.sequencer;
v_sequencer.rd_seqr = env.agent1.sequencer;
endfunction
endclss