了解sequencer与driver之间传递sequence item的握手过程,也掌握了sequence与item之间的关系。接下来对sequence挂载到sequencer的常用方法总结,可以通过这些方法和宏的介绍,了解到它们不同的使用场景面对多个sequence如果需要同时挂到sequence时,那就要面临这仲裁的需要,uvm_sequencer自带有仲裁特性,结合sequence的优先级设定,最终可以实现想要的效果。
class bus_trans extends uvm_sequence_item;
rand int data;
`uvm_object_utils_begin(bus_trans)
uvm_field_int(data,UVM_ALL_ON)
uvm_object_utils_end
endclass
class child_seq extends uvm_sequence;
`uvm_object_utils(child_seq)
...
task body();
uvm_sequence_item tmp;
bus_trans req;
tmp=create_item(bus_trans::get_type(),m_sequencer,"req");
void'($cast(req, tmp));
start_item(req);
req.randomize with {data==10;};
finish_item(req);
endtask
endclass
class top_seq extends uvm_sequence;
`uvm_object_utils(top_seq)
...
task body();
uvm_sequence_item tmp;
child_seq cseq;
bus_trans req;
//create child secuence and items
cseg=child_seq::type_id::create("cseq");
tmp=create_item(bus_trans::get_type(),m_sequencer,"req");
//send child sequence via start()
cseq.start(m_secquencer,this);
//send sequence item
void'($cast(req, tmp));
start_item(req);
req.randomize with {data==20;};
finish_item(req);
endtask
endclass
class sequencer extends uvm_sequencer;
`uvm_component_utils(sequencer)
...
endclass
class driver extends uvm_driver;
`uvm_component_utils(driver)
...
task run_phase(uvm_phase phase);
REQ tmp;
bus_trans req;
forever begin
seq_item_port.get_next_item(tmp);
void'($cast(req, tmp));
`uvm_info("DRV",$sformatf("got a item \n %s", req.sprint()), UVM_LOW)
seq_item_port.item_done();
end
endtask
endclass
class env extends uvm_env;
sequencer sqr;
driver drv;
`uvm_component_utils(env)
...
function void build_phase(uvm_phase phase);
sqr=sequencer::type_id::create("sqr", this);
drv=driver::type_id::create("drv", this);
endfunction
function void connect_phase(uvm_phase phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclass
class test1 extends uvm_test;
env e;
`uvm_component_utils(test1)
...
function void build_phase(uvm_phase phase);
e=env::type_id::create("e", this);
endfunction
task run_phase(uvm_phase phase);
top_seq seq;
phase.raise_objection(phase);
seq=new();
seq.start(e.sqr);
phase.drop_objection(phase);
endtask
endclass
输出结果:
UVM_INFO @ 0:uvm_test_top.e.drv [DRV] got a item
...
UVM_INFO @ 0:uvm_test_top.e.drv [DRV] got a item
...
在这段代码中,主要使用了两种方法。第一个方法是针对将sequence挂载到sequencer上的应用。
uvm_sequence::start(uvm_sequencer_base sequencer,
uvm_sequence_base parent_sequence=null
int this_priority = -1,bit call_ pre_post=11)
在上面的代码中, child_seq被嵌套到top_seq中,继而在挂载时需要指定parent_sequence;而在test一层调用top_seq时,由于它是root sequence,则不需要再指定parent sequence,这一点需要注意。另外,在调用挂载sequence时,需要对这些sequence进行例化。
uvm_sequence::start_item(uvm_sequence_item item,int set_priority=-1,
uvm_sequencer_base sequencer=null);
uvm_sequence::finish_item(uvm_sequence_item item,int set_priority=-1)
发送sequence/item方法解析
从这一点建议来看,对于一个item的完整传送,sequence要在sequencer一侧获得通过权限,才可以顺利将item发送至driver。可以通过拆解这些步骤得到更多的细节:
如果对比start()方法和start_item()/finish_item(),首先要分清它们面向的挂载对象是不同的。
item发送时相关方法的执行顺序如下:
很多情况start_item会立马返回;
正是通过几个sequence/item宏来打天下的方式,可以通过uvm_do/uvm_do_with来发送无论是sequence还是item。这种不区分对象是sequence还是item的方式,带来了不少便捷。
不同的宏,可能会包含创建对象的过程也可能不会创建对象。例如uvm_do/uvm_do_with会创建对象,而uvm_send则不会创建对象,也不会将对象做随机处理,因此要了解它们各自包含的执行内容和顺序。
此外还有其它的宏,例如,将优先级作为参数传递的uvm_do_prio uvm_do_on_prio等,还有专门针对sequence的uvm_create_seq/uvm_do_seq/uvm_do_seq_with等宏。
class child_seq extends uvm_sequence;
...
task body();
bus_trans req;
`uvm_create(req)
`uvm_rand_send_with(req,{data==10;})
endtask
endclass class top_seq extends uvm_sequence;
...
task body();
child_seq cseq;
bus_trans req;
// send child sequence via start()
`uvm_do(cseq)
//send secquence item
`uvm_do_with(req,{data==20;})
endtask
endclass
在发送sequence/item的几点建议: