在第一节中我们提过,为什么不把 transaction 实例化、随机和驱动全部放入 driver 中完成,我们验证的主要工作量,除了搭建验证环境之外,还有一大工作-拼凑场景case,其中不同场景中 transaction 的发送给数量和组织形式各有差异,我们如果把 transaction 放入driver 中,就需要经常改动 driver ,如果将驱动协议部分放入 driver 中,而在 sequnce 中完成 transaction 的实例化和随机化任务,我们创建新 case 时仅需要新建一个 sequence 即可。
上述过程如下图所示:
采用 sequence + sequencer + driver 实现驱动有以下优势:
a.sequence 、sequencer 和driver 三者之间分工合作,任务明确
b.driver 仅实现依据验证 Spec 实现驱动协议部分,可以重用
c.sequence 可以在上层对 transaction 进行管理组织
d.具有更好的重用性-不同的 sequence 实现不同的场景
e.具有更好的管控性如控制 sequence 的执行顺序及其不同 sequnece 之间的同步
1.什么是 sequence
上文提到,子弹,弹夹和枪的比喻,想必大家都有映像,sequence 就像一个弹夹,里面装了很多"子弹",而这里的"子弹"就是 transaction, 弹夹可长可短,只要子弹型号一致(同一种 transaction),就能通过 sequencer 和 driver 把数据驱动给 DUT。在下图中,有三个 sequence 挂载于同一个 sequncer 上(当然也可不同时间挂在其中一个 sequence),通过 driver 进行数据驱动,其中 sequencer 和 driver 是共同使用的。
1.1.sequence 实例
class my_transaction extends uvm_sequence_item;
`uvm_object_utils(my_transaction )
rand bit[47:0] dmac;
rand bit[47:0] smac;
constrain dma_cons{
dmac inside {[0:100]};
smac inside {[8:90]};
}
function void pre_randomize();
endfunction
function void post_randomize();
endfunction
...
endclass
class my_sequence extends uvm_sequence(# my_transaction )
`uvm_object_utils(my_sequence)
task body();
repeat(item_cnt) begin
`uvm_do(req);
get_response(req);
end
endtask
endclass
首先,我们要根据验证 Spec 实现 my_transaction(sequence_item 类),主要是完成随机变量的定义和约束(constrain),其中 pre_randomize() 函数会在 sequence_item 在调用 randomize() 函数前自动调用,同理 post_randomize() 为其后自动调用,这两个函数为空函数,需要用户根据自己的需要实现;
第二,实现 my_sequence 类,它必须继承于 uvm_sequence,(# my_transaction )为 uvm_sequence 参数,如果不指定则默认为 uvm_sequence_item类型,同时必须实现 body() 函数,它会在调用 sequence 启动是自动被调用。最后需要说明一下 'uvm_do(req), 这是一个 uvm library 定义的宏,它会完成 my_transaction 的实例化、随机化和驱动任务,在收到 driver 的反馈信息后,才结束此次发送,否则会一直等待。其中的 req 也为 uvm library 在 uvm_sequence 中定义成员变量,只要继承于它,即可直接用,其类型为 my_transaction(默认为 uvm_sequence) ;
第三,需要将 my_sequence 挂载于能发送 (# my_transaction ) 的 sequencer 上;
第四,启动 sequence。后续两项在本节后续会详细讲述。
2.2.sequence 管控性实例
class my_sequence extends uvm_sequence(# my_transaction )
`uvm_object_utils(my_sequence)
clk_rst_seq seq_clk;
reg_cfg_seq seq_ral;
data_trans_seq seq_data;
task body();
`uvm_do(s