文章目录
前言
在我们DUT的RTL中,经常会有很多的FIFO,很多时候,我们需要检查这些FIFO的空满,是否对系统有影响。本文主要介绍如何在验证环境中,随机force FIFO的空满。
本文基于UVM的框架,自顶向下进行描述,先介绍sequence中的实现,再介绍random_fifo_force的具体实现。
一、fifo_force_smoke_vseq
在fifo_force_smoke_vseq中,只需要利用fork–join_any,开两个进程,一个进程是执行base sequence中的body(),另外一个进程是执行random_fifo_force()。
class fifo_force_smoke_vseq extends base_vseq;
//...
task body();
fork
super.body();
random_fifo_force();
join_any
endtask : body
endclass : fifo_force_smoke_vseq
二、random_fifo_force
实现fifo的随机force,需要实现以下几个步骤:
1 从文件读入需要force fifo的路径;
2 对force的实现进行封装;
3 随机需要force的信号和时间;
2.1 从文件读入force的路径
从文件读入force路径的代码实现如下:
string fifo_list = ""
if($value$plusargs("fifo_list=%s", fifo_list)) begin
`uvm_info(`gfn, $sformatf("Loading fifo list %s", fifo_list), UVM_LOW)
end
fifo_list_reader rd = new();
rd.read_from_file(fifo_list);
其中,fifo_list_reader的实现思路是,拿到文件句柄后,按行读出文件路径,匹配tb开头的字符串,再将低有效或者高有效的路径分别存入sig_path和sig_n_path,实现代码如下:
class fifo_list_reader;
string sig_path[$];
string sig_n_path[$];
string lines[$];
function new();
endfunction //new()
function automatic void read_from_file(string fname);
integer fp = $fopen(fname, "r");
string line;
string head = "tb";
while($fgets(line, fp)) begin
if(line.len() > 2 && line[0] == head[0] && line[1] == head[1]) begin
line = line.substr(0, line.len()-2);
lines.push_back(line);
end
end
$fclose(fp);
assert (lines.size() % 2 == 0) else begin
`uvm_fatal("FIFO_LIST_READER", $sformatf("Line size not even! %d", lines.size()))
end
for(int i = 0; i < lines.size(); i += 2) begin
string line1 = lines[i];
string line2 = lines[i+1];
if(line1.len() == line2.len() + 2) begin
sig_n_path.push_back(line1);
sig_path.push_back(line2);
end
else if(line2.len() == line1.len() + 2) begin
sig_n_path.push_back(line2);
sig_path.push_back(line1);
end
else begin
`uvm_fatal("FIFO_LIST_READER", $sformatf("Unrecognized pattern!\]\n%s\n%s", line1, line2))
end
end
assert (sig_path.size() == sig_n_path.size()) else begin
`uvm_fatal("FIFO_LIST_READER", $sformatf("path size n equal: %d vs %d", sig_path.size(), sig_n_path.size()))
end
foreach(sig_path[i]) begin
`uvm_info("FIFO_LIST_READER", sig_path[i], UVM_LOW)
end
endfunction
endclass //fifo_list_reader
2.2 对force的实现进行封装
将2.1中读入的路径,分别封装好force的实现,放入fifo_forcer的大数组中,方便后续随机挑选。
fifo_full_empty_forcer fifo_forcer[$];
@(negedge clk_rst_vif.rst); //等待复位释放
foreach(rd.sig_path[i]) begin
sec_fifo_full_empty_forcer forcer = new(rd.sig_path[i], rd.sig_n_path[i]);
fifo_forcer.push_back(forcer);
end
其中,fifo_full_empty_forcer的实现思路是,在new函数,通过rtl_handler,对RTL force路径进行封装,再在不同的方法中去操作这个封装的句柄,实现代码如下:
class fifo_full_empty_forcer;
rtl_handler#(1) sig;
rtl_handler#(1) sig_n;
bit on = 0;
function new(string rtl_path, string rtl_n_path);
sig = new(rtl_path);
sig_n = new(rtl_n_path);
endfunction //new()
function void force_val(bit value = 1);
assert(sig.force_val(value));
assert(sig_n.force_val(~value));
endfunction
task automatic force_time(bit value, time f_time);
if(on) begin
`uvm_fatal("FIFO_FORCER", "Already on!")
end
fork
`uvm_info("FIFO_FORCER", $sformatf("%s for %t", sig.path, f_time), UVM_HIGH)
sig.force_time(value, f_time);
sig_n.force_time(~value, f_time);
handle_on(f_time);
join_none
endtask //automatic force_time
// total delay is 4 * f_time
task automatic handle_on(time f_time);
on = 1;
#(4 * f_time);
on = 0;
endtask //automatic
function void release_val();
assert(sig.release_val());
assert(sig_n.release_val());
endfunction
endclass //fifo_full_empty_forcer
底层rtl_handler的具体实现如下:
class rtl_handler #(int WIDTH);
string path;
function new(string rtl_path);
path = rtl_path;
endfunction
function int force_val(logic[WIDTH-1:0] value);
return uvm_hdl_force(path, value);
endfunction
task automatic force_time(logic[WIDTH-1:0] value, time f_time);
assert(this.force_val(value)) else begin
`uvm_fatal("SEC_RTL_HANDLER", $sformatf("Error force path %s", path))
end;
#f_time;
assert(this.release_val()) else begin
`uvm_fatal("SEC_RTL_HANDLER", $sformatf("Error release path %s", path))
end;
endtask //automatic force_time
function int release_val();
return uvm_hdl_release(path);
endfunction
function int read(output logic[WIDTH-1:0] value);
return uvm_hdl_read(path, value);
endfunction
endclass //rtl_handler #(int WIDTH)
2.3 随机需要force的信号和时间
随机选取信号,随机force的时间长度,执行force
forever begin
int idx;
int signal_size = fifo_forcer.size();
std::randomize(idx) with {
idx < signal_size;
idx >= 0;
};
if(fifo_forcer[idx].on == 0) begin
int time_ns;
std::randomize(time_ns) with {
time_ns dist {
[10:40] := 40,
[41:100] := 20,
[101:400] := 10
};
};
fifo_forcer[idx].force_time(1, time_ns * 1ns);
end
repeat($urandom_range(1,10))@(negedge cfg.clk_rst_vif.clk);
end
总结
本文主要介绍DUT中FIFO的full和empty的随机force思路,并给出了具体的代码实现。