知识点:
iff:在时间控制中添加修饰词iff,只有当iff后面的条件为真的时候,@时间才会触发。
数据采样:SV会默认为某个covergroup创建bin,用户也可以自己定义,如果采样变量的范围过大而有没有指定bin,那么系统会自动的分配64个bin,可以使用auto_bin_max来指定创建最大bin的数目。条件覆盖率:可以使用关键词iff给covergroup添加条件,这种做法经常用于在复位期间关闭覆盖以忽略不合理的触发条件,可以使用start和stop来控制各个covergroup各个独立实例。
覆盖点:一个覆盖组可以包含多个覆盖点,覆盖点元素可以包含显示bins和隐示bins
覆盖点的交叉覆盖率:
交叉覆盖名:cross 交叉覆盖点1,交叉覆盖点2;
忽略bin:可以使用ignore_bins来排除那些不计算功能的值域,最终他们并不会计入covergroup的覆盖率中
非法bin:使用illegal_bins对特定的bin进行标示。
排除部分cross bin:通过使用ignore_bins 、binsof和intersect分别指定covergroup和值域,这样可以清除很多不关心的cross bin。
1、编译:
选择与设计相关的文件.v
点击右键,选择 compile -> compile properties,在弹出设置栏的 coverage 一栏中, 如图选择以下选项,然后点击 OK。(只收集与设计相关的覆盖率)
2、仿真:
仿真命令:
vsim -i -classdebug -solvefaildebug -coverage -coverstore D:/questasim_file/lab5/coverage -testname mcdf_full_random_test -sv_seed random +TESTNAME=mcdf_full_random_test -l mcdf_full_random_test.log work.tb
-coverage:会在仿真时产生代码覆盖率数据,功能覆盖率数据则默认会生成,与此选项无关.
-coverstore COVERAGE_ STORAGE_ PATH:这个命令是用来在仿真在最后结束时,生成覆盖率数据并且存储到 COVERAGE_ STORAGE_ PATH.你可以自己制定 COVERAGE_STORAGE_ PATH,但需要注意路径名中不要包含中文字符。
-testname. TESTNAME:这个选项是你需要添加本次仿真的 test 名称,你可以使用 同+TESTNAME 选项一样的 test 名称。仿真结束后 , 将在 COVERAGE_STORAGE_PATH 下产生一个覆盖率数据文件 { TESTNAME}_{SV_SEED}.data
仿真命令:
run -all
利用仿真器直接查看代码覆盖率或者功能覆盖率:选中 View -> Coverage -> "Code Coverage Analysys"和” Covergroups"。
查看代码覆盖率:那么选择新添加的 Analysis 窗口,然后逐个点击Sim 窗口中 DUT 层次中的个别模块。
功能覆盖率:
3、合并覆盖率:
统一把生成在 COVERAGE_STORAGE_PATH下面生成的 xxx.data 覆盖率数据做合并。
vcover merge -out merged_coverage.ucdb D:/questasim_file/lab5/coverage
合并多个数据,功能覆盖率和代码覆盖率明显提高。
4、分析覆盖率:
选择 Tools -> Coverage Report-> HTML,按照下图所示进行勾选
忽略寄存器中高位没有翻转的位:参考路科验证MCDF_svlab5笔记_Hardworking_IC_boy的博客-优快云博客_合并覆盖率
5、总体分析:
实验五是在实验四的基础上,添加了一个组件mcdf_coverage, 定义了五个covergroup,然后在new里面分别例化,四个采样任务,对五个covergroup进行采样。
寄存器读写测试:
covergroup cg_mcdf_reg_write_read;
addr: coverpoint reg_vif.mon_ck.cmd_addr {
type_option.weight = 0;
bins slv0_rw_addr = {`SLV0_RW_ADDR};
bins slv1_rw_addr = {`SLV1_RW_ADDR};
bins slv2_rw_addr = {`SLV2_RW_ADDR};
bins slv0_r_addr = {`SLV0_R_ADDR };
bins slv1_r_addr = {`SLV1_R_ADDR };
bins slv2_r_addr = {`SLV2_R_ADDR };
}
cmd: coverpoint reg_vif.mon_ck.cmd {
type_option.weight = 0;
bins write = {`WRITE};
bins read = {`READ};
bins idle = {`IDLE};
}
cmdXaddr: cross cmd, addr {
bins slv0_rw_addr = binsof(addr.slv0_rw_addr);
bins slv1_rw_addr = binsof(addr.slv1_rw_addr);
bins slv2_rw_addr = binsof(addr.slv2_rw_addr);
bins slv0_r_addr = binsof(addr.slv0_r_addr );
bins slv1_r_addr = binsof(addr.slv1_r_addr );
bins slv2_r_addr = binsof(addr.slv2_r_addr );
bins write = binsof(cmd.write);
bins read = binsof(cmd.read );
bins idle = binsof(cmd.idle );
bins write_slv0_rw_addr = binsof(cmd.write) && binsof(addr.slv0_rw_addr);
bins write_slv1_rw_addr = binsof(cmd.write) && binsof(addr.slv1_rw_addr);
bins write_slv2_rw_addr = binsof(cmd.write) && binsof(addr.slv2_rw_addr);
bins read_slv0_rw_addr = binsof(cmd.read) && binsof(addr.slv0_rw_addr);
bins read_slv1_rw_addr = binsof(cmd.read) && binsof(addr.slv1_rw_addr);
bins read_slv2_rw_addr = binsof(cmd.read) && binsof(addr.slv2_rw_addr);
bins read_slv0_r_addr = binsof(cmd.read) && binsof(addr.slv0_r_addr);
bins read_slv1_r_addr = binsof(cmd.read) && binsof(addr.slv1_r_addr);
bins read_slv2_r_addr = binsof(cmd.read) && binsof(addr.slv2_r_addr);
}
endgroup
type_option.weight = 0表示不关心addr:covergroup和cmd:covergroup这两个覆盖组,表示权重为0,然后重新声明。
寄存器稳定性测试:主要是对于非法地址的读写操作。
covergroup cg_mcdf_reg_illegal_access;
addr: coverpoint reg_vif.mon_ck.cmd_addr {
type_option.weight = 0;
bins legal_rw = {`SLV0_RW_ADDR, `SLV1_RW_ADDR, `SLV2_RW_ADDR}; //合法地址的读写范围
bins legal_r = {`SLV0_R_ADDR, `SLV1_R_ADDR, `SLV2_R_ADDR}; //合法地址的读范围
bins illegal = {[8'h20:$], 8'hC, 8'h1C}; //非法地址的范围
}
cmd: coverpoint reg_vif.mon_ck.cmd {
type_option.weight = 0;
bins write = {`WRITE};
bins read = {`READ};
}
wdata: coverpoint reg_vif.mon_ck.cmd_data_m2s { //写数据
type_option.weight = 0;
bins legal = {[0:'h3F]}; //00_0000到11_1111是合法的
bins illegal = {['h40:$]}; //剩下的都是非法的
}
rdata: coverpoint reg_vif.mon_ck.cmd_data_s2m {
type_option.weight = 0;
bins legal = {[0:'hFF]};
illegal_bins illegal = default; //超过低八位的都是非法的
}
cmdXaddrXdata: cross cmd, addr, wdata, rdata { //组合
bins addr_legal_rw = binsof(addr.legal_rw);
bins addr_legal_r = binsof(addr.legal_r);
bins addr_illegal = binsof(addr.illegal);
bins cmd_write = binsof(cmd.write);
bins cmd_read = binsof(cmd.read);
bins wdata_legal = binsof(wdata.legal);
bins wdata_illegal = binsof(wdata.illegal);
bins rdata_legal = binsof(rdata.legal);
bins write_illegal_addr = binsof(cmd.write) && binsof(addr.illegal);
bins read_illegal_addr = binsof(cmd.read) && binsof(addr.illegal);
bins write_illegal_rw_data = binsof(cmd.write) && binsof(addr.legal_rw) && binsof(wdata.illegal);
bins write_illegal_r_data = binsof(cmd.write) && binsof(addr.legal_r) && binsof(wdata.illegal);
}
endgroup
数据通道开关测试:特定的通道关闭,en为0,但是vaild为高,测试数据能否写入成功。
covergroup cg_channel_disable;
ch0_en: coverpoint mcdf_vif.mon_ck.chnl_en[0] { //enable为0
type_option.weight = 0;
wildcard bins en = {1'b1};
wildcard bins dis = {1'b0};
}
ch1_en: coverpoint mcdf_vif.mon_ck.chnl_en[1] { //enable为1
type_option.weight = 0;
wildcard bins en = {1'b1};
wildcard bins dis = {1'b0};
}
ch2_en: coverpoint mcdf_vif.mon_ck.chnl_en[2] {
type_option.weight = 0;
wildcard bins en = {1'b1};
wildcard bins dis = {1'b0};
}
ch0_vld: coverpoint chnl_vifs[0].mon_ck.ch_valid {
type_option.weight = 0;
bins hi = {1'b1};
bins lo = {1'b0};
}
ch1_vld: coverpoint chnl_vifs[1].mon_ck.ch_valid {
type_option.weight = 0;
bins hi = {1'b1};
bins lo = {1'b0};
}
ch2_vld: coverpoint chnl_vifs[2].mon_ck.ch_valid {
type_option.weight = 0;
bins hi = {1'b1};
bins lo = {1'b0};
}
chenXchvld: cross ch0_en, ch1_en, ch2_en, ch0_vld, ch1_vld, ch2_vld {
bins ch0_en = binsof(ch0_en.en);
bins ch0_dis = binsof(ch0_en.dis);
bins ch1_en = binsof(ch1_en.en);
bins ch1_dis = binsof(ch1_en.dis);
bins ch2_en = binsof(ch2_en.en);
bins ch2_dis = binsof(ch2_en.dis);
bins ch0_hi = binsof(ch0_vld.hi);
bins ch0_lo = binsof(ch0_vld.lo);
bins ch1_hi = binsof(ch1_vld.hi);
bins ch1_lo = binsof(ch1_vld.lo);
bins ch2_hi = binsof(ch2_vld.hi);
bins ch2_lo = binsof(ch2_vld.lo);
bins ch0_en_vld = binsof(ch0_en.en) && binsof(ch0_vld.hi);
bins ch0_dis_vld = binsof(ch0_en.dis) && binsof(ch0_vld.hi);
bins ch1_en_vld = binsof(ch1_en.en) && binsof(ch1_vld.hi);
bins ch1_dis_vld = binsof(ch1_en.dis) && binsof(ch1_vld.hi);
bins ch2_en_vld = binsof(ch2_en.en) && binsof(ch2_vld.hi);
bins ch2_dis_vld = binsof(ch2_en.dis) && binsof(ch2_vld.hi);
}
endgroup
优先级测试:不同通道配置不同的优先级。
covergroup cg_arbiter_priority; //配置每个channel的priority
ch0_prio: coverpoint arb_vif.mon_ck.slv_prios[0] {
bins ch_prio0 = {0};
bins ch_prio1 = {1};
bins ch_prio2 = {2};
bins ch_prio3 = {3};
}
ch1_prio: coverpoint arb_vif.mon_ck.slv_prios[1] {
bins ch_prio0 = {0};
bins ch_prio1 = {1};
bins ch_prio2 = {2};
bins ch_prio3 = {3};
}
ch2_prio: coverpoint arb_vif.mon_ck.slv_prios[2] {
bins ch_prio0 = {0};
bins ch_prio1 = {1};
bins ch_prio2 = {2};
bins ch_prio3 = {3};
}
endgroup
下行从端低带宽测试:测试下行从端的延迟
covergroup cg_formatter_length; //真实情况下。还是需要通过cross进行组合
id: coverpoint fmt_vif.mon_ck.fmt_chid {
bins ch0 = {0};
bins ch1 = {1};
bins ch2 = {2};
illegal_bins illegal = default;
}
length: coverpoint fmt_vif.mon_ck.fmt_length {
bins len4 = {4};
bins len8 = {8};
bins len16 = {16};
bins len32 = {32};
illegal_bins illegal = default;
}
endgroup