MCDF实验——Lab5
Lab5主要完成如何定义覆盖率,如何从验证计划到测试用例的实现,最后再到覆盖率的量化。验证量化分为代码覆盖率和功能覆盖率。
一、编译
在编译过程中,需要对于设计相关的文件设置额外的覆盖率编译选项。
- 只选中与设计相关的文件
- 点击右键,选择compile->compile properties,在弹出设置栏的coverage一栏中,如图选择以下选项,然后点击OK。
- 完成所有文件的编译“Compile All”。这一步将在编译DUT文件时生成代码覆盖率的模型。
二、仿真
在仿真窗口(transcript)中,执行仿真命令
vsim -i -classdebug -solvefaildebug -coverage -coverstore D:/questasim64_10.6c/Project/lab5/lab5 -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。-testname TESTNAME
:这个选项是你需要添加本次仿真的test名称,可以使用同+TESTNAME
选项一样的test名称。这样在仿真结束后,将在COVERAGE_STORAGE_PATH下产生一个覆盖率数据文件“{TESTNAME}_{SV_SEED}.data”。由于仿真时传入的种子是随机值,因此每次提交测试,在测试结束后都将产生一个独一无二的覆盖率数据。
执行run -all
,等待跑完仿真
执行quit -sim
命令之后,可以发现文件下中多了一个data文件
仿真结束以后,可以查看代码覆盖率
还可以查看本次仿真所收集到的功能覆盖率
三、合并覆盖率
运行不同的仿真,或者运行同一个test,都会生成独一无二的数据库,可以将生成的.data覆盖率数据文件做合并。
执行如下命令
vcover merge -out merged_coverage.ucdb D:/questasim64_10.6c/Project/lab5/lab5
可以打开合并后的UCDB覆盖率数据库,打开这个数据库之后,会发现合并后的数据库要比之前单独提交的任何一次测试在仿真结束时的该次覆盖率都要高。
四、分析覆盖率
可以选择Tools->Coverage Report->HTML生成报告
通过分析覆盖率,需要修改约束或者创建新的测试最终来达到验证完备性的要求。
五、覆盖率代码分析
相比于Lab4,Lab5在mcdf_pkg.sv
新添加了一个组件mcdf_coverage
class mcdf_coverage;local virtual chnl_intf chnl_vifs[3]; local virtual arb_intf arb_vif; local virtual mcdf_intf mcdf_vif;local virtual reg_intf reg_vif;local virtual fmt_intf fmt_vif;local string name;local int delay_req_to_grant;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); }endgroupcovergroup 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]};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);}endgroupcovergroup cg_channel_disable;ch0_en: coverpoint mcdf_vif.mon_ck.chnl_en[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] {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);}endgroupcovergroup cg_arbiter_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}; }endgroupcovergroup cg_formatter_length;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;}endgroupcovergroup cg_formatter_grant();delay_req_to_grant: coverpoint this.delay_req_to_grant {bins delay1 = {1};bins delay2 = {2};bins delay3_or_more = {[3:10]};illegal_bins illegal = {0};}endgroupfunction new(string name="mcdf_coverage");this.name = name;this.cg_mcdf_reg_write_read = new();this.cg_mcdf_reg_illegal_access = new();this.cg_channel_disable = new();this.cg_arbiter_priority = new();this.cg_formatter_length = new();this.cg_formatter_grant = new();endfunctiontask run();fork this.do_reg_sample();this.do_channel_sample();this.do_arbiter_sample();this.do_formater_sample();joinendtasktask do_reg_sample();forever begin@(posedge reg_vif.clk iff reg_vif.rstn);this.cg_mcdf_reg_write_read.sample();this.cg_mcdf_reg_illegal_access.sample();endendtasktask do_channel_sample();forever begin@(posedge mcdf_vif.clk iff mcdf_vif.rstn);if(chnl_vifs[0].mon_ck.ch_valid===1|| chnl_vifs[1].mon_ck.ch_valid===1|| chnl_vifs[2].mon_ck.ch_valid===1)this.cg_channel_disable.sample();endendtasktask do_arbiter_sample();forever begin@(posedge arb_vif.clk iff arb_vif.rstn);if(arb_vif.slv_reqs[0]!==0 || arb_vif.slv_reqs[1]!==0 || arb_vif.slv_reqs[2]!==0)this.cg_arbiter_priority.sample();endendtasktask do_formater_sample();forkforever begin@(posedge fmt_vif.clk iff fmt_vif.rstn);if(fmt_vif.mon_ck.fmt_req === 1)this.cg_formatter_length.sample();endforever begin@(posedge fmt_vif.mon_ck.fmt_req);this.delay_req_to_grant = 0;forever beginif(fmt_vif.fmt_grant === 1) beginthis.cg_formatter_grant.sample();break;endelse begin@(posedge fmt_vif.clk);this.delay_req_to_grant++;endendendjoinendtaskfunction void do_report();string s;s = "\n---------------------------------------------------------------\n";s = {s, "COVERAGE SUMMARY \n"}; s = {s, $sformatf("total coverage: %.1f \n", $get_coverage())}; s = {s, $sformatf(" cg_mcdf_reg_write_read coverage: %.1f \n", this.cg_mcdf_reg_write_read.get_coverage())}; s = {s, $sformatf(" cg_mcdf_reg_illegal_access coverage: %.1f \n", this.cg_mcdf_reg_illegal_access.get_coverage())}; s = {s, $sformatf(" cg_channel_disable_test coverage: %.1f \n", this.cg_channel_disable.get_coverage())}; s = {s, $sformatf(" cg_arbiter_priority_test coverage: %.1f \n", this.cg_arbiter_priority.get_coverage())}; s = {s, $sformatf(" cg_formatter_length_test coverage: %.1f \n", this.cg_formatter_length.get_coverage())}; s = {s, $sformatf(" cg_formatter_grant_test coverage: %.1f \n", this.cg_formatter_grant.get_coverage())}; s = {s, "---------------------------------------------------------------\n"};rpt_pkg::rpt_msg($sformatf("[%s]",this.name), s, rpt_pkg::INFO, rpt_pkg::TOP);endfunctionvirtual function void set_interface(virtual chnl_intf ch_vifs[3] ,virtual reg_intf reg_vif,virtual arb_intf arb_vif,virtual fmt_intf fmt_vif,virtual mcdf_intf mcdf_vif);this.chnl_vifs = ch_vifs;this.arb_vif = arb_vif;this.reg_vif = reg_vif;this.fmt_vif = fmt_vif;this.mcdf_vif = mcdf_vif;if(chnl_vifs[0] == null || chnl_vifs[1] == null || chnl_vifs[2] == null)$error("chnl interface handle is NULL, please check if target interface has been intantiated");if(arb_vif == null)$error("arb interface handle is NULL, please check if target interface has been intantiated");if(reg_vif == null)$error("reg interface handle is NULL, please check if target interface has been intantiated");if(fmt_vif == null)$error("fmt interface handle is NULL, please check if target interface has been intantiated");if(mcdf_vif == null)$error("mcdf interface handle is NULL, please check if target interface has been intantiated");endfunctionendclass
首先定义了6个covergroup
covergroup cg_mcdf_reg_write_read;
covergroup cg_mcdf_reg_illegal_access;
covergroup cg_channel_disable;
covergroup cg_arbiter_priority;
covergroup cg_formatter_length;
covergroup cg_formatter_grant();
然后例化这6个covergroup
function new(string name="mcdf_coverage");this.name = name;this.cg_mcdf_reg_write_read = new();this.cg_mcdf_reg_illegal_access = new();this.cg_channel_disable = new();this.cg_arbiter_priority = new();this.cg_formatter_length = new();this.cg_formatter_grant = new();endfunction
然后通过4个采样任务进行采样
task run();fork this.do_reg_sample();this.do_channel_sample();this.do_arbiter_sample();this.do_formater_sample();joinendtask
这4个采样任务分别采样了6个covergroup
//do_reg_sample()
cg_mcdf_reg_write_read.sample();
cg_mcdf_reg_illegal_access.sample();//do_channel_sample()
cg_channel_disable.sample();//do_arbiter_sample()
cg_arbiter_priority.sample();//do_formater_sample()
cg_formatter_length.sample();
cg_formatter_grant.sample();
定义的mcdf_coverage
会在mcdf_env
中例化,并且调用cvrg.run()
和cvrg.do_report()
使其运行并生成测试报告。
重点是6个covergroup
cg_mcdf_reg_write_read
:寄存器读写测试
对所有控制、状态寄存器的读写进行测试。
covergroup cg_mcdf_reg_write_read;//要覆盖到6个寄存器地址,3个读写寄存器地址和3个只读寄存器地址addr: coverpoint reg_vif.mon_ck.cmd_addr {type_option.weight = 0; //权重设置为0,表示不关心此覆盖点的覆盖率,否则cross会出现很多的binbins 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 };//8bit地址实际上会生成256个bin,256-6=250会被平均分配到这6个bin中,//但默认max为64个bin,所以剩下的250要分配到64-6=58个bin里面}//覆盖读写指令cmd: coverpoint reg_vif.mon_ck.cmd {type_option.weight = 0;bins write = {`WRITE};bins read = {`READ};bins idle = {`IDLE};//cmd是2bit的,所以还有一个默认的bin}//交叉覆盖,哪些寄存器可以读写,哪些寄存器只读,通过不同指令对不同地址的寄存器的操作来进行覆盖cmdXaddr: cross cmd, addr {bins slv0_rw_addr = binsof(addr.slv0_rw_addr); //因为权重为0,所以需要再一次的声明,这样可以只关心所需要的bin即可,不会生成没用的binbins 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
cg_mcdf_reg_illegal_access
:寄存器稳定性测试
对非法地址进行读写测试,对控制寄存器的保留域进行读写测试,对状态寄存器进行写操作测试。
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;//数据合法范围,0~111111,即bit(0)使能信号、bit(2:1)优先级、bit(5:3)数据包长度都可以写bins legal = {[0:'h3F]}; //数据非法范围,bit(31:6)保留位,无法写入bins illegal = {['h40:$]};}//读数据覆盖点rdata: coverpoint reg_vif.mon_ck.cmd_data_s2m {type_option.weight = 0;//读数据合法范围,0~11111111,即bit(7:0)上行数据从端FIFO的可写余量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
cg_channel_disable
:数据通道开关测试
对每一个数据通道对应的控制寄存器域en配置为0,在关闭状态下测试数据写入是否通过。
covergroup cg_channel_disable;//3个数据通道的en信号覆盖点ch0_en: coverpoint mcdf_vif.mon_ck.chnl_en[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] {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};}//3个数据通道的valid信号的覆盖点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);//采集当valid拉高时,en拉高和拉低的情况数据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
cg_arbiter_priority
:优先级测试
将不同数据通道配置为相同或者不同的优先级,在数据通道使能的情况下进行测试。
covergroup cg_arbiter_priority;//把3个数据通道的优先级分别配置为0,1,2,3ch0_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
cg_formatter_length
:发包长度测试
将不同数据通道随机配置为各自的长度,在数据通道使能的情况下进行测试。
covergroup cg_formatter_length;//不同的数据通道是否都能发送数据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
cg_formatter_grant
:下行从端低带宽测试
将MCDF下行数据接收端设置为小存储量,低带宽的类型,由此使得在由formatter发送出数据之后,下行从端有更多的机会延迟grant信号的置位,用来模拟真实场景。
covergroup cg_formatter_grant();delay_req_to_grant: coverpoint this.delay_req_to_grant { //delay_req_to_grant是一个软件信号,即是mcdf_coverage中的一个成员变量,是计算出来的bins delay1 = {1};bins delay2 = {2};bins delay3_or_more = {[3:10]};//req和grant之间的间隔不允许为0illegal_bins illegal = {0};}endgroup
4个sample
采样
do_reg_sample()
:对寄存器进行采样
task do_reg_sample();forever begin//对于每一个时钟上升沿,就要对寄存器的读写、寄存器的非法操作做采样@(posedge reg_vif.clk iff reg_vif.rstn);this.cg_mcdf_reg_write_read.sample();this.cg_mcdf_reg_illegal_access.sample();endendtask
do_channel_sample()
:对数据通道做采样
task do_channel_sample();forever begin//对于每一个时钟上升沿,至少有一个channel的valid信号为1时,即有数据发送进来时,才对disable做采样@(posedge mcdf_vif.clk iff mcdf_vif.rstn);if(chnl_vifs[0].mon_ck.ch_valid===1|| chnl_vifs[1].mon_ck.ch_valid===1|| chnl_vifs[2].mon_ck.ch_valid===1)this.cg_channel_disable.sample();endendtask
do_arbiter_sample()
:对优先级做采样
task do_arbiter_sample();//对于每一个时钟的上升沿,至少有一个channel的req为1,即至少有一个channel要发送数据了,才对其优先级做采样forever begin@(posedge arb_vif.clk iff arb_vif.rstn);if(arb_vif.slv_reqs[0]!==0 || arb_vif.slv_reqs[1]!==0 || arb_vif.slv_reqs[2]!==0)this.cg_arbiter_priority.sample();endendtask
do_formater_sample()
:对grant
信号做采样
task do_formater_sample();forkforever begin//对于每一个时钟上升沿,当req为1时,对数据的长度做采样@(posedge fmt_vif.clk iff fmt_vif.rstn);if(fmt_vif.mon_ck.fmt_req === 1)this.cg_formatter_length.sample();endforever begin//当req拉高时,要通过变量delay_req_to_grant来计算延迟,对grant做采样@(posedge fmt_vif.mon_ck.fmt_req);this.delay_req_to_grant = 0; //初始化为0forever begin//只有grant拉高时,才对grant做采样,进而通过delay_req_to_grant的值得到延迟if(fmt_vif.fmt_grant === 1) beginthis.cg_formatter_grant.sample();break;endelse begin@(posedge fmt_vif.clk);this.delay_req_to_grant++;endendendjoinendtask
综上所述:对于覆盖率组件mcdf_coverage
,首先要定义covergroup
并指点coverpoint
,然后例化covergroup
,例化之后要做采样,接着在run()
中调用采样任务。
MCDF实验——Lab5相关推荐
- MCDF实验4(4)
目录 引言:接着上篇的MCDF实验4(3),解释一下添加的检查 1)通道 en=0 时的检查 2)arbiter 的仲裁功能的检查 在tb.sv 中 连接信号 引言:接着上篇的MCDF实验4(3),解 ...
- MCDF实验——Lab4
在之前的Lab3中,通过一个初具规模的MCDT的验证环境,学习到: 验证环境按照隔离的观念,应分为硬件DUT,软件验证环境,和处于信号媒介的接口interface. 对于软件验证环境,需要经历建立阶段 ...
- MCDF实验_lab0(0)
目录 一.MCDF功能描述[^1] MCDF结构 slave端口时序 formater端口时序 寄存器时序 二.代码分析 时间单位 信号 例化 产生时钟 产生复位 发送激励 三.Questasim的M ...
- MCDF实验_lab1(1)
目录 一.问题 二.实验要求 三.代码分析 时间单位 信号 例化 产生时钟 产生复位 发送激励模块 产生数据 实例化slave模块 发送激励 三.Questasim的Makefile[^2] 四.波形 ...
- ICS计算系统概论LC3汇编实验Lab5—中断、递归解决汉诺塔问题
Lab Purpose 完成用户程序的编写. 编写下面描述的键盘中断服务例程. condition: 用户程序: 汉诺塔的参数,记录为N,将用xFFFF初始化并存储在X3FFF内存中. 您的用户程序从 ...
- MCDF实验_lab4(4)
目录 一.框架图 二.代码分析 reg_chnl reg_trans,传输的数据包 reg_generator reg_driver reg_monitor reg_agent fmt_pkg fmt ...
- MCDF 实验4 (1)
目录 fmt_pkg.sv 代码分析 fmt_pkg.sv 中的 fmt_driver do_consume() 的代码解析 do_receive() 的代码解析 do_config() 的代码 ...
- HIT CSAPP 自设实验 Lab5 链接 Linkbomb 解析
之前的方法太坑了,我更新了一下phase2 _(:з」∠)_ 55555 直接复制过来排版太烂,我也懒得改了_(:з」∠)_,如果看的不舒服,移步: hahalidaxin's Github upd ...
- ucore_lab5实验报告
实验目的: 了解第一个用户进程创建过程 了解系统调用框架的实现机制 了解ucore如何实现系统调用sys_fork/sys_exec/sys_exit/sys_wait来进行进程管理 让用户进程在用户 ...
最新文章
- Android 使用 setImageResource 清空图片
- 预定义变量 - PHP手册笔记
- Android之发送短信后按钮(60秒)变灰色每隔一秒递减显示
- C语言代码规范(九)运算符优先级使用括号提高阅读性
- [Node.js] 模块化 -- fs文件读取模块
- 线上电商年货节,PSD分层模板,让“年味”触手可及~
- 用户登录自动注销问题
- android 获取程序名,Android_Android获取应用程序名称(ApplicationName)示例,MainActivity如下: 复制代码 代码 - phpStudy...
- Android AnimatedVectorDrawable
- 基于SSM的电影购票系统
- webstorm做项目第三天——开始登陆界面
- 量化交易——PEG策略
- 天空之镜?瑞士冰川?Nono,这里其实是新疆!
- 切图具体需要切什么内容_UI日常-切图切图怎么破?
- girl_noise.jpg恢复去噪
- Android第三方库收藏汇总
- SpringBoot项目——————签到与签退管理(源码分享)
- router-view添加key解决同一路由复用相同组件
- Yep MKdocs编辑器
- 基于RT-Thread+RA6M4的远程开机助手