Hierarchical Sequences
在处理Sequences时,考虑到测试平台可能会需要对不同功能测试,可以对功能进行分层拆解。在与每个代理相关联的最低层是API Sequences。利用API Sequence来完成工作的中间层是worker Sequence。最后,在控制整个测试顶部是一个虚拟sequence,它协调不同目标测序器上的工作sequence的运行
API Sequences
API sequence是sequence层次结构中的最低层。他们做的工作最少,因为他们在运行时做一个非常有针对性的行动。API sequence应该执行小的原子操作,比如在总线上执行读取、在总线上执行写、在总线上执行读修改写或等待中断或其他信号。API sequence将包含在systemverilog pkg中,该包定义了要在其上运行sequence的代理。两个示例API sequence将如下:
代码语言:javascript复制//API Sequence for doing a Read
class spi_read_seq extends uvm_sequence #(spi_item);
`uvm_object_utils(spi_read_seq)
const string report_id = "spi_read_seq";
rand bit [7:0] addr;
bit [15:0] rdata;
task body();
req = spi_item::type_id::create("spi_request"); start_item(req);
if ( !(req.randomize() with {req.addr == local::addr;} ))
`uvm_error(report_id, "Randomize Failed!") finish_item(req);
rdata = req.data;
endtask : body
task read(input bit [7:0] addr, output bit [15:0] read_data, input uvm_sequencer_base seqr, input uvm_sequence_base parent = null);
this.addr = addr; this.start(seqr, parent);
read_data = req.data;
endtask : read
endclass : spi_read_seq
//API Sequence for doing a Write
class spi_write_seq extends uvm_sequence #(spi_item);
`uvm_object_utils(spi_write_seq)
const string report_id = "spi_write_seq";
rand bit [7:0] addr;
rand bit [15:0] wdata;
task body();
req = spi_item::type_id::create("spi_request"); start_item(req);
if ( !(req.randomize() with {req.addr == local::addr;req.data == local::wdata; } ))
`uvm_error(report_id, "Randomize Failed!") finish_item(req);
endtask : body
task write(bit [7:0] addr, bit [15:0] write_data, uvm_sequencer_base seqr, uvm_sequence_base parent = null);
this.addr = addr;
this.wdata = write_data;
this.start(seqr, parent);
endtask : write
endclass : spi_write_seq
Worker Sequences
Worker sequence利用低级API sequence来构建中层sequence。这些中层sequence可以做诸如dut配置、加载内存等事情。通常,一个Worker sequence将只向一个sequencer发送单个sequence item。Worker sequence是这样的:
代码语言:javascript复制//Worker sequence for doing initial configuration for Module A
class moduleA_init_seq extends uvm_sequence #(spi_item);
`uvm_object_utils(moduleA_init_seq)
const string report_id = "moduleA_init_seq";
spi_read_seq read;
spi_write_seq write;
task body();
read = spi_read_seq::type_id::create("read");
write = spi_write_seq::type_id::create("write");
//Configure registers in Module
//Calling start
write.addr = 8'h20;
write.wdata = 16'h00ff;
write.start(m_sequencer, this);
//Using the write task
write.write(8'h22, 16'h0100, m_sequencer, this);
//Other register writes
//Check that Module A is ready
read.addr = 8'h2c;
read.start(m_sequencer, this);
if (read.rdata != 16'h0001)
`uvm_fatal(report_id, "Module A is not ready")
endtask : body
endclass : moduleA_init_seq
Virtual Sequences
virtual sequence用于调用和协调所有的Worker sequence。在大多数情况下,设计需要在发送随机数据之前进行初始化。virtual sequence可以调用初始化Worker sequence,然后调用其他Worker sequence,如果需要执行低级操作,还可以调用其他Worker sequence,甚至是API sequence。virtual sequence将包含对目标sequencer的句柄(推荐),或在virtual sequencer上运行,该virtual sequencer允许访问运行Worker sequence和API sequence所需的所有sequencer。下面就是一个例子
代码语言:javascript复制//Virtual Sequence controlling everything
class test1_seq extends uvm_sequence #(uvm_sequence_item);
`uvm_object_utils(test1_seq)
const string report_id = "test1_seq";
// These handles will be assigned by an init method in the test
uvm_sequencer_base spi_seqr;
uvm_sequencer_base modA_seqr;
uvm_sequencer_base modB_seqr;
moduleA_init_seq modA_init;
moduleB_init_seq modB_init;
moduleA_rand_data_seq modA_rand_data;
moduleB_rand_data_seq modB_rand_data;
spi_read_seq spi_read;
bit [15:0] read_data;
task body();
modA_init = moduleA_init_seq::type_id::create("modA_init");
modB_init = moduleB_init_seq::type_id::create("modB_init");
modA_rand_data = moduleA_rand_data_seq::type_id::create("modA_rand_data");
modB_rand_data = moduleB_rand_data_seq::type_id::create("modB_rand_data");
spi_read = spi_read_seq::type_id::create("spi_read");
//Do Initial Config
fork
modA_init.start(spi_seqr, this);
modB_init.start(spi_seqr, this);
join
//Now start random data (These would probably be started on
different sequencers for a real design) fork
modA_rand_data.start(modA_seqr, this);
modB_rand_data.start(modB_seqr, this);
join
//Do a single read to check completion
spi_read.read(8'h7C, read_data, spi_seqr, this);
if (read_data != 16'hffff)
`uvm_error(report_id, "Test Failed!")
endtask : body
endclass : test1_seq