最近项目中需要function覆盖率,所以就专门看了这部分知识,那么开始了!
主要是声明一个covergroup,让这个covergroup随着事件sample_trans响应,sample_trans在monitor的main函数中触发。systemverilog默认是把coverpoint分成64组,我在第一句里面通过{option.auto_bin_max = 10;}把分组数改成10试试效果。
在transaction和generator那里改下随机化:
`ifndef TRANSACTION
`define TRANSACTION
class transaction;
//declaring the transaction items
rand bit [63:0] a;
rand bit [63:0] b;
rand bit [63:0] return_value;
constraint set_to_0 {return_value == 64'h0000000000000000;}
function void display(string name);
$display("-------------------------");
$display("- %s ",name);
//$display("-------------------------");
$display("- a = %0h, b = %0h",a,b);
$display("- return_value = %0h",return_value);
$display("-------------------------");
endfunction
endclass
`endif
首先是直接在monitor里改出functional coverage功能
`include "transaction.sv"
`include "scoreboard.sv"
class monitor;
virtual intf vif;
transaction trans;
event sample_trans;
mailbox mon2scb;
scoreboard sb;
covergroup cover_trans @(sample_trans);
a:coverpoint trans.a {option.auto_bin_max = 10;}
b:coverpoint trans.b;
return_value:coverpoint trans.return_value;
//{option.auto_bin_max = 10;}
endgroup
function new(virtual intf vif,mailbox mon2scb,scoreboard sb);
this.vif = vif;
this.mon2scb = mon2scb;
this.sb = sb;
this.cover_trans = new();
endfunction
task main;
begin
trans = new();//这里没有用FIFO来.get,所以要new;
@(posedge vif.clk);
trans.a = vif.a;
trans.b = vif.b;
@(posedge vif.clk);
trans.return_value = vif.return_value;
@(posedge vif.clk);
mon2scb.put(trans);
trans.display("[ Monitor: transaction from interface to Monitor ]");
@(posedge vif.clk);
sb.check_output;
->sample_trans;
end
endtask
endclass
接下来在env的主循环后加上显示采样结果的语句:
`include "transaction.sv"
`include "generator.sv"
`include "driver.sv"
`include "monitor.sv"
`include "input_monitor.sv"
`include "scoreboard.sv"
class environment;
generator gen;
scoreboard scb;
driver driv;
monitor mon;
input_monitor in_mon;
mailbox gen2driv;
mailbox mon2scb;
mailbox in_mon2scb;
mailbox driv2in_mon;
virtual intf vif;
function new(virtual intf vif);
this.vif = vif;
gen2driv = new();
mon2scb = new();
in_mon2scb = new();
driv2in_mon = new();
gen = new(gen2driv);
scb = new(mon2scb,in_mon2scb);
driv = new(vif,gen2driv,driv2in_mon);
mon = new(vif,mon2scb,scb);
in_mon = new(vif,driv2in_mon,in_mon2scb,scb);
//cover_trans = new;
endfunction
task pre_test();
$display("pre_test:driv.reset:begin");
driv.reset();//在driver中,控制interface来实现reset
$display("pre_test:driv.reset:end");
in_mon.main();
#1000;
mon.main();
endtask
integer i;
task test();
gen.read_input_output;
for(i=1;i<=45;i++)
begin
$display("i:%d",i);
gen.main(i);//生成一个trans,给a和b赋值,放入gen2driv_mailbox中
driv.main();//从gen2driv_mailbox中取ab数放自己肚子里,再传给interface,等1000ns,然后从interface中取return_value出来用display显示
//driver的main中有1000ns延时
in_mon.main();
mon.main();//从interface中取数出来,先放自己肚子里,然后把结果put进mon2scb_mailbox
//加入sample
end
//$display("Coverage = %0.2f %%",mon.cover_trans.get_inst_coverage());
$display("Coverage = %0.2f %%",mon.cover_trans.a.get_inst_coverage());
$display("Coverage = %0.2f %%",mon.cover_trans.b.get_inst_coverage());
$display("Coverage = %0.2f %%",mon.cover_trans.return_value.get_inst_coverage());
endtask
task post_test();
endtask
//run task
task run;
$display("pre_test");
pre_test();
$display("test");
test();
$display("post_test");
post_test();
$display("finish");
$finish;
endtask
endclass
在generator里也很简单地改一改。
`include "transaction.sv"
class generator;
parameter NUMBER = 46;
//declaring transaction class
transaction trans;
reg [63:0] a_input[0:NUMBER-1];
reg [63:0] b_input[0:NUMBER-1];
reg [63:0] z_output[0:NUMBER-1];
task read_input_output;
begin
$readmemh("a_input.txt",a_input);
$readmemh("b_input.txt",b_input);
$readmemh("z_output.txt",z_output);
end
endtask
mailbox gen2driv;
event ended;
function new(mailbox gen2driv);
this.gen2driv = gen2driv;
endfunction
task main(integer i);
trans = new();
/*
trans.a = a_input[i];
trans.b = b_input[i];
trans.return_value = z_output[i];
*/
trans.randomize();
trans.display("[ Generator: transaction generated in Generator");
gen2driv.put(trans);
//-> ended; //triggering indicatesthe end of generation
endtask
endclass
结果:
这里有个情况,就是我这边没有专门写计算64位浮点运算的程序,所以随机化后没法比对计算结果,不过这个DUT也在FPGA上测试过了,肯定是没有问题的,就给自己省点事,把return_value设成0,直接不在scoreboard比较就好了。咱们主要是试下functional coverage。
其实我们用久违的统计学思考一下,一个64长度的平均分布,要出现取样1000次某个区间都取不到值的P值,肯定是无比地小。
反过来想,如何确定我们的随机次数该为多少比较合适呢?这个情况完全就是数理统计里中心极限那一章的很基础的计算题。我们设置一个P值比如为0.01%,反过来求要达到这个P值水平下,长度64的平均分布的采样次数就可以了。乌拉,中心极限定律无处不在!