chapter 23 UVM Sequence
此前,我们通过tester/put&get port/driver将激励和测试平台分割开来,但是我们并没有将data stimulus从structure中分离出来。tester需要创建新的transaction,并将其送至测试平台,这意味着tester需要选择transaction的顺序,并经其送至测试平台。我们可以通过override transaction type控制data的随机化,但是我们必须重写整个tester来改变transaction的发送数量,顺序等。一个好的测试平台需要将order of transaction(the stimulus)和测试平台组件testbench structure分离开来。
- 我们通过创建三个类来实现此功能:
- Fibonacci test:使用TinyALU来计算Fibonacci sequence;
- Full Random test:使用约束的随机数据实现功能覆盖目标
- Intleave test:Fibonacci & random test的随机执行
此前,为了实现以上三个test我们需要完全重构tester,这样违背了代码重用性和易维护性,UVM sequence将stimulus和structure分割开来,这允许我们创建测试平台并运行不同的激励。我们接下来将使用UVM sequence将transaction-level的测试平台转成使用sequence的测试平台。
23.1 Transaction level -> sequence testbench
23.1.1 Create TinyALU Sequence Item
- sequence_item和command_transaction的区别:
- 扩展自uvm_seuqnce_item而不是uvm_transaction
- 增加result变量,记录DUT计算的结果
- 其余部分完全一致。
class sequence_item extends uvm_sequence_item; //uvm_sequence_item扩展自uvm_transaction
`uvm_object_utils(sequence_item);
function new(string name = "");
super.new(name);
endfunction : new
rand byte unsigned A;
rand byte unsigned B;
rand operation_t op;
shortint unsigned result; //新增result 变量
......
endclass : sequence_item
23.1.2 Replace tester with uvm_sequencer
- 在不适用uvm_agent的前提下,我们仍需要在env中例化各个组件。此时其中的tester需要负责两项功能,导致难以维护和重用。我们希望tester只是实现传递sequence items至driver,至于sequence items的顺序我们希望有另一个模块来负责,同时tester也将改名为sequencer,仅仅实现sequence items的传递功能。
- sequencer从sequence中取出一系列的sequence items,并发送至driver,uvm提供了一个uvm_sequencer基类,我们直接使用其定义即可,如下图。
- 使用typedef关键字定义sequencer为参数化的uvm_sequencer类。
23.1.3 Update driver to support sequence
- UVM定义了基类uvm_driver(component)并且将其与uvm_sequencer关联起来,我们只需要扩展uvm_driver,并且重构run_phase即可。
- 继承uvm_driver的时候,我们便继承了sequence_item_port,我们可以使用sequence_item_port从sequencer中获取sequence item。
class driver extends uvm_driver #(sequence_item);
`uvm_component_utils(driver)
virtual tinyalu_bfm bfm;
function void build_phase(uvm_phase phase);
if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm))
`uvm_fatal("DRIVER", "Failed to get BFM")
endfunction : build_phase
task run_phase(uvm_phase phase);
sequence_item cmd;
forever begin : cmd_loop
shortint unsigned result; //get_next_item一直阻塞至sequencer将sequence item送入端口
seq_item_port.get_next_item(cmd); //和put/get_port、analysis port类似方式获取数据
bfm.send_op(cmd.A, cmd.B, cmd.op, result);
cmd.result = result;
seq_item_port.item_done(); //将数据通过send_op送到BFM,并将result数据传回
end : cmd_loop //通过调用item_done函数告诉sequencer,可以开始发送下一个sequence item
endtask : run_phase
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
endclass : driver
23.1.4 Instance driver & sequencer in ENV and connect them
- 在测试平台中,使用sequencer替换tester,并将其和driver连接起来,如下图:
- sequencer和driver之间的链接不需要fifo。
class env extends