• MCDF实验5:凛冬的寒风(从verilog到SV的入门lab5)


    前言: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); 
          }
        endgroup
    
        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]};
            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
    
        covergroup 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);
          }
        endgroup
    
        covergroup 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}; 
          }
        endgroup
    
        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
    
        covergroup 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};
          }
        endgroup
    
        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
    
        task run();
          fork 
            this.do_reg_sample();
            this.do_channel_sample();
            this.do_arbiter_sample();
            this.do_formater_sample();
          join
        endtask
    
        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();
          end
        endtask
    
        task 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();
          end
        endtask
    
        task 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();
          end
        endtask
    
        task do_formater_sample();
          fork
            forever begin
              @(posedge fmt_vif.clk iff fmt_vif.rstn);
              if(fmt_vif.mon_ck.fmt_req === 1)
                this.cg_formatter_length.sample();
            end
            forever begin
              @(posedge fmt_vif.mon_ck.fmt_req);
              this.delay_req_to_grant = 0;
              forever begin
                if(fmt_vif.fmt_grant === 1) begin
                  this.cg_formatter_grant.sample();
                  break;
                end
                else begin
                  @(posedge fmt_vif.clk);
                  this.delay_req_to_grant++;
                end
              end
            end
          join
        endtask
    
        function 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);
        endfunction
    
        virtual 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");
        endfunction
      endclass
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291

    上述代码定义了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();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    然后例化这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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    然后通过4个采样任务进行采样,分别采样了6个covergroup。

        task run();
          fork 
            this.do_reg_sample();
            this.do_channel_sample();
            this.do_arbiter_sample();
            this.do_formater_sample();
          join
        endtask
    
    
    //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();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在mcdf_env中对mcdf_coverage例化,并且调用cvrg.run()和cvrg.do_report()运行并生成测试报告。

    6个covergroup分别对应之前的6个测试。

    • 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会出现很多的bin
            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 };
            //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即可,不会生成没用的bin
            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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • cg_arbiter_priority:优先级测试,将不同数据通道配置为相同或者不同的优先级,在数据通道使能的情况下进行测试。
        covergroup cg_arbiter_priority;
          //把3个数据通道的优先级分别配置为0,1,2,3
          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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 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之间的间隔不允许为0
            illegal_bins illegal = {0};
          }
        endgroup
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    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();
          end
        endtask
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 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();
          end
        endtask
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 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();
          end
        endtask
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • do_formater_sample():对grant信号做采样
        task do_formater_sample();
          fork
            forever begin
              //对于每一个时钟上升沿,当req为1时,对数据的长度做采样
              @(posedge fmt_vif.clk iff fmt_vif.rstn);
              if(fmt_vif.mon_ck.fmt_req === 1)
                this.cg_formatter_length.sample();
            end
            forever begin
              //当req拉高时,要通过变量delay_req_to_grant来计算延迟,对grant做采样
              @(posedge fmt_vif.mon_ck.fmt_req);
              this.delay_req_to_grant = 0;		//初始化为0
              forever begin
              	//只有grant拉高时,才对grant做采样,进而通过delay_req_to_grant的值得到延迟
                if(fmt_vif.fmt_grant === 1) begin
                  this.cg_formatter_grant.sample();
                  break;
                end
                else begin
                  @(posedge fmt_vif.clk);
                  this.delay_req_to_grant++;
                end
              end
            end
          join
        endtask
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    对于覆盖率组件mcdf_coverage,首先定义covergroup并指点coverpoint,并例化covergroup,例化之后做采样,接着在run()中调用采样任务。

    1. 编译

    先编译所有的设计文件,再通过“Compile All”编译全部文件,。
    在这里插入图片描述

    2. 仿真

    编译完成在仿真窗口(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.tb1
    
    • 1
    • 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文件。仿真结束以后,可以查看代码覆盖率、功能覆盖率。
    在这里插入图片描述
    在这里插入图片描述

    3. 合并覆盖率

    运行不同的仿真,或者运行同一个test,都会生成独一无二的数据库,可以将生成的.data覆盖率数据文件做合并。

    vcover merge -out merged_coverage.ucdb D:/questasim64_10.6c/Project/lab5/lab5
    
    • 1

    在这里插入图片描述

    在这里插入图片描述

    4、分析覆盖率

    选择Tools->Coverage Report->HTML生成报告。
    在这里插入图片描述

  • 相关阅读:
    分割数据清洗
    jarsigner和apksigner对apk/aab签名
    安装kibana
    【HackTheBox】 meow
    前端新手Vue3+Vite+Ts+Pinia+Sass项目指北系列文章 —— 第三章 项目创建
    AIDL的使用
    【JAVA】Web服务器—Tomcat
    css / scss 样式变量
    【Apollo】自动驾驶技术的介绍
    优秀的Elasticsearch Java 客户端-Jest
  • 原文地址:https://blog.csdn.net/jackack/article/details/127665967