【UVM COOKBOOK】Sequences||Hierarchical Sequences

2021-12-06 15:21:21 浏览数 (1)

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

0 人点赞