众所周知,在验证的过程中,非常重要的一件事情就是给激励到dut。这是必不可少的一件事情。uvm在这件事情上也下了不少功夫。
一个需要发激励给dut的agent,封装了driver,monitor,sequencer。最普遍的一个产生激励的方式是,激励从sequence开始到sequencer再到driver,再回到sequence的数据通路。这个数据通路的起点之一:`uvm_do 系列宏。
那今天就从`uvm_do系列宏开始,看看`uvm_do系列宏究竟做了哪些事情。
`uvm_do系列宏都是由`uvm_do_pri_on_with (SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS)来定义的,比如`uvm_do的源码为:
`define uvm_do(SEQ_OR_ITEM) \
`uvm_do_on_pri_with(SEQ_OR_ITEM, m_sequencer, -1, {})
其他的`uvm_do_on等等都是类似的,只不过是`uvm_do_on_pri_with的参数变化而已,不需要给的就是默认值。
那我们来看`uvm_do_pri_on_with的源码:
//==================================================================
`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
//=======================================================================
如果括号内第一个参数为sequence,也就是继承自uvm_sequence类型的,主要就是做了一件事:seq.start(sqr); start 任务主要就是执行sequence的body任务。
如果括号内参数为transaction,也就是继承自uvm_sequence_item类型的,可以概括为3件事:`uvm_create_on(),start_item(),finish_item()。
`uvm_create_on()主要就是例化一个transaction,并且在factory中有创建记录的。
start_item主要做了两件事;1. 调用sequencer.wait_for_grant();2.pre_do:pre_do这个task没做事情,如果需要使用的话,自己重载使用,pre_do源码如下:
virtual task pre_do(bit is_item);
return;
endtask
//=================================================================
sequencer.wait_for_grant()的原型如下:
extern virtual task wait_for_grant(uvm_sequence_base sequence_ptr,int item_priority = -1, bit lock_request = 0);
主要做的事情:简单来讲就是new 一个uvm_sequence_request类型放进队列排队,具体展开来讲(待补充)
class uvm_sequence_request;
bit grant;
int sequence_id;
int request_id;
int item_priority;
process process_id;
uvm_sequencer_base::seq_req_t request;
uvm_sequence_base sequence_ptr;
endclass
//=================================================
然后是finish_item,原型:
virtual task finish_item (uvm_sequence_item item,
int set_priority = -1);
主要做了4件事情:mid_do(item);
sequencer.send_request(this, item);
sequencer.wait_for_item_done(this, -1);
post_do(item);
mid_do() ,post_do()没有具体内容,类似于pre_do(),如果需要使用的话,自己重载使用;
sequencer.send_request(this, item):主要做的事是设置transaction_id和sequence_id,然后把这个tr放进m_req_fifo中。具体展开来讲(待补充)
sequencer.wait_for_item_done()的原型如下:
task uvm_sequencer_base::wait_for_item_done(uvm_sequence_base sequence_ptr, int transaction_id);
这个任务会阻塞,直到等到item_done语句执行后。因为item_done是在driver里面调用的,所以这里有和driver的同步。
后续会有对driver和sequencer的行为探索。