SV理论知识六:代码覆盖率、功能覆盖率以及断言覆盖率

    1. 在类中可以定义多个覆盖组,一个功能点的测试可以对应一个覆盖组,每个覆盖组可以单独使用使能来控制,每个组可以单独设置触发的事件
    2. 覆盖组的覆盖点可以会自动建仓或者自定义仓,对于自动建仓,会根据采样点的取值范围来生成仓,例如一个N比特的就有2的N次方个仓,
       自动建仓可以通过option.auto_bin_max设置最大的bin数(默认是64个仓)来控制划分的bin(自动按照数值范围切分,每个仓平分,枚举类型不适用);
       如果是自己定义的仓,若没有把所有的取值范围都列在bins里面,则不会自动去建仓,覆盖率的计算也只是在自定义的仓里面计算
       覆盖点采样的可以是表达式、变量、总线信号或者设计里面的信号
       (1) 如何定义含有多个值的仓(拼接符的应用)
           bins a = {[0:7]}
       (2) 如何批量指定仓名(中括号的应用)
           bins a[] = {[0:7]}
        总的来说,在名字后面加[]表明是为每一个取值建一个仓,使用{}表示拼接多个数值
        wildcard;
        wildcard bins g12_15 = { 4'b11?? };         //只要在1100~1111间的任何一个踩到了,就收到了;
        wildcard bins g12_15_array[] = { 4'b11?? }; //加了[], 会给每一个符合条件的都产生一个bin
    3. 在覆盖组包含形式参数、覆盖点、触发事件以及选项
       option.per_instance: 对一个covergroup 例化多次,默认情况下SV会将所有实例的覆盖率合并到一起。单独列出每个covergroup实例的覆盖率,
                            则设置覆盖选项option.per_instance=1(只能在覆盖组中使用,不能在覆盖点或者bin中使用)
       option.per_instance: 如果有多个covergroup实例,可以通过参数来对每一个实例传入单独注释。这些注释最终会显示在覆盖率数据的总结报告中,便于分析报告。
       option.cross_num_print_missing: 将没有命中的仓和没有采样值的仓也报告出来    
    4. 覆盖率的计算方法
       单个覆盖点的计算方法:该覆盖点被击中的bins除以该覆盖点总的bins
       整个覆盖组的覆盖率计算方法:该组的所有覆盖点的组合  
       整体功能覆盖点的计算方法:所有覆盖组的覆盖率的组合 
    5. 每个覆盖组、覆盖点以及仓都可以命名
    6. 覆盖组在哪里使用?
       下面展示常规的几种做法:
       (1) 在env中例化,定义的coverage类继承于uvm_component组件类,
           需要在new函数中实例化覆盖组,使得覆盖组件在实例化时也把覆盖组也实例化了
           采样的是总线上的信号,因此需要通过configdb设置虚拟接口或者通过set_interface进行设置
           在run_phase中定义不同覆盖组的采样时刻,在run_phase中执行的语句,会交给uvm_component的phase机制统一调度
       (2) 
    7. 覆盖组对什么进行采样?
        (1) 采样monitor监听到的事务,由于monitor监听的事务是动态变化的,也就是说虽然采样的是某种事务类型的某个变量,但是具体所属的实例是会变化的
        (2) 直接采样总线上的事务,信号线不会发生变化,只需要一致监听感兴趣的信号线即可(monitor的事务也是从总线上抓取的)
------------------------------------------------------------------------------------*/
// 
// 可以存在多个覆盖组,一个覆盖组可以实例化多次,可以使用start()以及stop()函数来使能某个覆盖组实例
covergroup cg(ref bit[2:0] port, input int mid) @(event); 
    // 这里采用ref引用的方式来实现通过外部传入port的值,可以实现不同实例监听不同端口的功能
    // 同时,这里的mid形参,可以控制一些仓的取值范围

    // iff(event),条件事件,只有在event发生时才收集该覆盖点
    port:coverpoint port iff(event){
    option.weight = 0;            // 权重为0,指的是不收集该点的覆盖率,这里只使用在精细指定交叉覆盖中
    option.goal = ;
    option.comment = "";
    option.at_least = ;            // 至少击中几次
    option.auto_bin_max = ;        // 划分为几个域
    ignore_bins igb = ;            // 忽略哪些仓
    illegal_bins ilb = ;        // 哪些仓是非法的,出现则报错结束仿真
    bins b1 = {[2:7], 10};        // 表示一个仓,取值{2,3,4,5,6,7,10}
    bins b2[] = {[8:9]};        // 两个仓,自动命名成b2_8,b2_8
    bins t1 = (0=>1), (1=>2), (2=>3); // 翻转信号,只要有一个翻转的信号满足,则该仓被击中;
    wildcard bins w1 = {3'b??1};// 通配
    } // 注意,这里不用加分号
    
    kind:coverpoint kind{
    bins k1 = {[1:3]};
    option.weight = 0;
    }

    // 使用交叉覆盖组,并且排除掉一些情况,可以直接使用intersect来排除覆盖点的具体取值,也可以直接binsof(bins_name)来指定某个仓
    cross kind,port{
    ignore_bins hi = binsof(port) intersect(7);        // port==7;
    ignore_bins md = binsof(port) intersect(0) &&     // port==0且kind==[1:2];
    binsof(kind) intersect([1:2]);
    }

    // 可以使用精细地指定交叉覆盖,而不用排除过多地情况
    cross kind,port{
    bins k1p2 = binsof(port) intersect(2) && binsof(kind) intersect(1);
    }
endgroup : cg

$get_coverage();             // 在全局层面上获取所有覆盖组的总覆盖率(返回一个实数)
CoverGroup::get_coverage();  // 获取该覆盖组所有实例的覆盖率
cg_inst.get_inst_coverage(); // 获取特定的覆盖组实例的覆盖率

/*-----------------------------断言和断言覆盖率-------------------------------------------------
  一、 SVA
  1. 立即断言,类似if else语句那样,只能在程序语块中使用,用于动态仿真,没有时间的概念
     并发断言,基于时钟周期进行(在每个感兴趣的时钟周期都会触发检查),可以放置于procedural block、module、interface及program中,不能出现在class中
              在静态(形式)验证及动态仿真工具中均可以应用。
  2. 并发断言的使用流程
  (1) 在sequence中定义检查的序列
      sequence name_of_sequence;
         <test_expression>;
      endsequence
  (2) 将多个sequence包含在property关键字中
      property property_name;
         <test expression>; or
         <complex sequence expression>;
      endproperty
  (3) assertion_name:assert/cover property (property_name);
  
  二、 断言语法
      1. [=m] 非连续(无需跟随)重复操作符, 重复发生多次,但不需要连续发生, 也不需要在满足条件时马上匹配(不需要跟随)
         [*m] 连续重复运算符,重复发生多次,且连续发生
         [->m] 非连续跟随重复符,a非连续重复3次,只在第3次重复时刻点匹配(跟随的含义)。

  三、一些实际例子
      1. 保持不变/有变化:$stable() 当前和上一个周期保持不变
      2. 访问过去的周期:$past(req, 2) 一般会把过去周期的某个数据保存在变量里面,然后再和后续的数据作比较
      3. 表示同时:
         (1) seq1 and seq2 同时开始,可以不同时结束,序列的终点是最长的那个
         (2) seq1 intersect seq2 同时开始,同时结束
        以上是表示两个序列的,都是包含时钟,若是表示同一时刻的某两个信号满足的条件,那应该是&&(与) || (或)
      4. 贯穿某个序列:seq1/exp throughout seq2 序列或者表达式贯穿seq2期间均成立
      5. 包含关系:seq1 within seq2 表示seq2序列包含了seq1,可以不用同时开始或者同时结束
      6. 序列的终点:seq.ended 序列是否已经结束
      7. 如何表示连续的两次读写操作:$rose(penable) |-> (##[2:$] ($rose(penable)))
      8. 下一次传输开始前某个值保持不变:判断到下一次传输的条件下,用past取出前一个的值与上次传输是否一致

    四、内置的一些函数
       1. $countbits(expression, a) 计算expression中数值为a的位数
      2. $countones(expression) 计数表达式中为1的比特的个数
         等同于$countbits(expression, `1)
      3. $onehot(expression) 检查是否只有一个比特位为1
         等同于$countbits(expression, `1)==1
      4. $isunknown(expression) 检查是否有任意比特为 X或 Z.
         等同于$countbits(expression, `X, `Z)!=0

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值