uvm数字验证覆盖率收集


概述

在进行芯片验证时,最重要的一个环节就是完成对dut的覆盖率收集工作,覆盖率主要分为下面三类:

1.代码覆盖率

2.功能覆盖率

3.断言覆盖率

如何完成覆盖率收集?

  代码覆盖率:是衡量验证进展的最简易的方式。它的作用是检查代码是否冗余,设计要点是否遍历,被检测的对象是RTL代码,而代码覆盖率的检测一般由工具自动生成的。行覆盖率(Line coverage)、分支覆盖率(Branch coverage)、路径覆盖率(Path Coverage)、翻转覆盖率(Toggle coverage)、条件覆盖率(Conditional coverage)、有限状态机覆盖率(FSM coverage)

在makefile中添加-cm line+fsm+tgl+cond+assert可完成相对应的代码覆盖率的收集。(在编译和运行时都需添加)

  功能覆盖率:功能覆盖率是一个用户定义的度量标准,它测量了设计规范的多少部分,通过测试计划中的特性枚举,已经被执行。它可以用来衡量是否有兴趣的场景、角落用例、规格不变量,或者其他适用的设计条件(作为测试计划的特性捕获)已经被观察、验证和测试。 

  这里简单介绍下如果你收集的代码覆盖率很高但是功能覆盖率缺很低,这个可能是:

  1. design没有完全按照功能spec文档规格实现所有功能,设计不完善;
  2. 验证平台monitor监视器存在漏洞,设计代码实现了功能但没有覆盖到他们;
  3. 功能正确,但是发送的激励不对,对应功能的覆盖率无法收集。

如果你收集的功能覆盖率很高但是代码覆盖率缺很低,这可能是:

  1. 设计代码没有按照spec实现功能,在design中是无效代码,
  2. 用户定义的功能覆盖率收集存在错误,没有完全定比覆盖率收集的边界,测试计划未捕获所有设计功能/场景/边界,或者缺少功能覆盖率监视器。代码覆盖率中未覆盖的设计代码可能会映射到这些功能上。
  3. 在实现功能覆盖率监视器时可能存在潜在的错误,导致它们收集了错误的覆盖率。因此,在验证项目中,对用户定义的功能覆盖率指标及其实现进行适当的检查很重要。

 

定义一个coverage class,在类中指定你要收集的coveragegroup和coveragepoint,也可指定你要收集的仓bins。

`ifndef GUARD_COVERAGE
`define GUARD_COVERAGE

class coverage;
packet pkt;

covergroup switch_coverage;

  length : coverpoint pkt.length;
  da     : coverpoint pkt.da {
              bins p0 = { `P0 }; 
              bins p1 = { `P1 }; 
              bins p2 = { `P2 }; 
              bins p3 = { `P3 }; } 
  length_kind : coverpoint pkt.length_kind;
  fcs_kind : coverpoint pkt.fcs_kind;
  
  all_cross:  cross length,da,length_kind,fcs_kind;
endgroup

function new();
  switch_coverage = new();
endfunction : new

task sample(packet pkt);
 this.pkt = pkt;
 switch_coverage.sample();
endtask:sample

endclass

`endif

在scoreboard完成coverage模块的调用,coverage cov = new() 新建所要使用的类,cov.sample(pkt_exp)采样pkt_exp数据包。

`ifndef GUARD_SCOREBOARD
`define GUARD_SCOREBOARD

class Scoreboard;

mailbox drvr2sb;
mailbox rcvr2sb;
coverage cov = new();

function new(mailbox drvr2sb,mailbox rcvr2sb);
  this.drvr2sb = drvr2sb;
  this.rcvr2sb = rcvr2sb;
endfunction:new


task start();
  packet pkt_rcv,pkt_exp;
  forever
  begin
    rcvr2sb.get(pkt_rcv);
    $display(" %0d : Scorebooard : Scoreboard received a packet from receiver ",$time);
    drvr2sb.get(pkt_exp);
    if(pkt_rcv.compare(pkt_exp)) 
    begin
       $display(" %0d : Scoreboardd :Packet Matched ",$time);
    cov.sample(pkt_exp);
    end
    else
      error++;
  end
endtask : start

endclass

`endif

断言覆盖率:通过设定断言,一般完成接口时序相关的覆盖率收集。如AHB总线时序在对同一个地址先做写操作再不间隔做读操作,可使用property指定两次操作的地址是相同的,在cover该property。

  property p_write_read_burst_trans;
    logic[31:0] addr;
    @(posedge clk) ($rose(penable) && pwrite, addr=paddr) |-> (##2 ($rose(penable) && !pwrite && addr==paddr)); 
  endproperty: p_write_read_burst_trans
  cover property(p_write_read_burst_trans);

如何查看收集后的覆盖率?

收集后的覆盖率保存在simv.vdb文件夹中,可使用urg工具转成可视化的html文件或直接使用dve工具查看simv.vdb

直接查看指令:dve -full64 -cov -dir simv.vdb&

urg转成html文件:urg -dir simv.vdb -report urgReport 

相同代码不同tc的覆盖率合并:urg -full64 -dir tc1.vdb tc2.vdb -dbname merged.vdb -report urgReport

转成后的html文件可通过 firefox urgReport/dashboard.html查看