这一篇在干嘛?

仿真跑通了不代表测全了。代码覆盖(Code Coverage)回答的是另一个问题:你的测试激励到底执行了源代码里的哪些语句、分支、条件、表达式?哪些逻辑位从没翻转过?哪些 FSM 状态从没进过?这一章教你打开覆盖统计、读懂各种覆盖窗口和图标、排除不该统计的代码,并生成文本或 HTML 覆盖报告,把「没测到的代码」一眼找出来。示例设计仍是一个控制行为级存储器的有限状态机加 test bench。

编译设计

开启代码覆盖的流程很简单:编译设计文件时指定要收集哪些覆盖统计,然后加载设计并让 Questa SIM 产出这些统计。

示例文件路径:

  • Verilog – <install_dir>/questasim/examples/tutorials/verilog/coverage
  • VHDL – <install_dir>/questasim/examples/tutorials/vhdl/coverage

本课以 Verilog 版本为例,有 VHDL license 的读者可改用 VHDL 版本。

  1. 新建目录,把 <install_dir>/questasim/examples/tutorials/verilog/coverage 下所有文件复制进去(VHDL 用户复制 vhdl/coverage 目录)。
  2. 启动 Questa SIM 并切换目录:
    • UNIX shell 输入 vsim,或 Windows 下点 Questa SIM 图标;欢迎对话框出现则点 Close。
    • 选 File > Change Directory 切到练习目录。
  3. 创建工作库:在 Questa SIM> 提示符输入 vlib work
  4. 编译所有设计文件:
    • Verilog:输入 vlog *.v
    • VHDL:输入 vcom *.vhd
  5. 指定要收集的覆盖统计类型。在 Questa SIM> 提示符输入:
vopt +cover=bcesxf test_sm -o test_sm_opt

+cover=bcesxf 参数让 Questa SIM 收集 branch(分支)、condition(条件)、expression(表达式)、statement(语句)、extended toggle(扩展翻转)和 FSM(有限状态机)覆盖统计。更多覆盖类型见 User’s Manual 的 Overview of Code Coverage Types。 -o 参数为优化后的设计指定名字(这里是 test_sm_opt),vopt 命令必须带此参数。 默认情况下,Questa SIM 对所有设计执行优化(见 User’s Manual 的 Optimizing Designs with vopt)。

FPGA 语境

+cover=bcesxf 的每个字母对应一类覆盖:b=branch、c=condition、e=expression、s=statement、x=extended toggle、f=FSM。做 FPGA 设计验证时,statement + branch(bs)通常是最基本的底线,toggle 覆盖对检查「上电后某些位从没动过」特别有用——这往往对应着没被复位或没被驱动的逻辑。

加载并运行设计

指定覆盖统计类型后,就可以加载并运行设计了。

  1. 加载设计。在 Questa SIM> 提示符输入(加载优化后的设计):
vsim -coverage test_sm_opt

三个覆盖窗口会分别在三个主窗口组中打开:Code Coverage Analysis、Instance Coverage 和 Coverage Details(Figure 13-1)。

三个代码覆盖窗口

在 Code Coverage Analysis 窗口中可以做 statement、branch、condition、expression、FSM 和 toggle 六种覆盖分析。窗口中每一行都有图标,标明该行的元素(语句、分支、条件或表达式)是已执行、未执行还是被排除。Table 13-1 是代码覆盖图标说明。

Table 13-1 代码覆盖图标:

图标含义
该行所有语句、分支、条件或表达式均已执行
该行有多种覆盖未执行
True 分支未执行(BC 列)
False 分支未执行(BC 列)
条件未执行(Hits 列)
表达式未执行(Hits 列)
分支未执行(Hits 列)
语句未执行(Hits 列)
E该行应用了有效覆盖排除;行上每一项都被排除,无命中
E□部分被排除项有命中
E□部分项被排除,其余未被排除项全部命中
部分项被排除,部分未被排除项缺覆盖
该行应用了自动排除。光标悬停在 EA 上会弹出显示排除原因的 tooltip

在 Analysis 工具栏(Figure 13-2)中选择要做的分析。

Analysis 工具栏

当前打开的是哪种分析,看 Code Coverage Analysis 窗口的标题栏即可(Figure 13-3)。

标题栏显示当前分析类型

默认情况下,第一次打开 Code Coverage Analysis 窗口显示 Statement Analysis;之后再打开时显示上次选择的分析窗口。

  1. 运行仿真。在 VSIM> 提示符输入:
run 1 ms
  1. 以启用代码覆盖的方式加载设计后,Questa SIM 会在 Files 和 Structure (sim) 窗口中添加几个覆盖数据列(Figure 13-4)。用水平滚动条可以看到更多覆盖列(你的结果可能与图中不同)。

Structure (sim) 窗口中的覆盖数据列:

NameSpecified pathFull pathTypeStmt CountStmt HitsStmt %Stmt GraphBran
simvsim.wlfC:/Tutorial/…
sm.vsm.vC:/Tutorial/… verilog252288.000
sm_seq.vsm_seq.vC:/Tutorial/… verilog161593.750
beh_sram.vbeh_sram.vC:/Tutorial/… verilog6583.333
test_sm.vtest_sm.vC:/Tutorial/… verilog777090.909
  1. 通过 View > Coverage 菜单可以打开和关闭覆盖窗口(Figure 13-5)。

Coverage 菜单

  1. 所有覆盖窗口都可以缩放、重排和解除停靠:拖动任意边框缩放窗口;拖动标题栏的把手(标题栏中间的三排点)或标签移动窗口;选中窗口后拖出主窗口、或点标题栏右上角的 Dock/Undock 按钮解除停靠;再点一次该按钮可重新停靠。
  2. 下一步练习里我们会更仔细地看几个覆盖窗口。

查看覆盖数据

看看不同覆盖窗口里显示的数据。

  1. 在 Structure (sim) 窗口查看覆盖数据:
    • 选中 sim 标签,用水平滚动条查看覆盖列中的数据。设计中每个对象都有一份覆盖数据。
    • 选 Files 标签切到 Files 窗口并向右滚动。右键任意列名,选 Change Column Visibility,再从弹出列表中选择,即可更改显示哪些覆盖数据列。

Configure Columns 对话框中的列:

Branch %Full path
Branch CountSpecified path
Branch GraphStates %
Branch HitsStates Count
Condition %States Graph
Condition HitsStmt %
Condition CountStmt Count
Condition GraphStmt Graph
Condition HitsStmt Hits
Expression %Stmt Graph
Expression CountToggle %
Expression HitsToggle nodes
Expression GraphToggled graph
FEC Condition %Toggles hit
FEC Condition CountTransitions %
FEC Condition GraphTransitions Count
FEC Expression %Transitions Graph
FEC Expression CountTransitions Hits
FEC Expression GraphType
FEC Expression Hits

勾选的列显示,未勾选的隐藏。每列的显示/隐藏状态在 Questa SIM 多次启动之间保持不变。 2. 在 Code Coverage Analysis 窗口的 Statement Analysis 视图查看覆盖数据:

  • 若 Statement Analysis 视图未显示,在 Analysis 工具栏选 Statement Analysis(Figure 13-7)。

选择 Statement Analysis

  • 在 Files 窗口选择不同文件,Statement Analysis 视图会更新为所选文件的覆盖数据。
  • 双击 Statement Analysis 视图中的任意条目,可在 Source 窗口中显示该行。
  1. 在 Coverage Details 窗口查看 toggle 覆盖细节:
    • 在 Analysis 工具栏选 Toggle Analysis,切换到 Toggle Analysis 视图(Figure 13-7)。
    • 点击 Details 标签打开 Coverage Details 窗口。若 Details 标签不可见,在主菜单选 View > Coverage > Details。
    • 在 Toggle Analysis 中选中任意对象,在 Coverage Details 窗口中查看其覆盖细节(Figure 13-8)。

解除停靠的 Coverage Details 窗口

  1. 查看实例覆盖数据:

    • 点击 Instance 标签切到 Instance Coverage 窗口。若 Instance 标签不可见,在主菜单选 View > Coverage > Instance Coverage。

    Instance Coverage 窗口以扁平、非层次视图显示每个实例的覆盖统计。双击任意实例可在 Source 窗口中显示其源代码。

Instance Coverage 窗口内容示例:

InstanceDesign unitDesign unit typeTotal coverageStmt graphStmt countStmts hitStmts mi
/test_smtest_smModule52.6%7770
/test_sm/ill_opTaskFunction100%22
/test_sm/rd_wdTaskFunction100%88
/test_sm/wt_blkTaskFunction100%1010
/test_sm/wt_wdTaskFunction100%88
/test_sm/ctrlTaskFunction0%50
/test_sm/nopTaskFunction100%22
/test_sm/sm_seq0sm_seqModule65.6%1615
/test_sm/sm_seq0/…smModule85.3%2522
/test_sm/sram_0beh_sramModule45.4%65

Source 窗口中的覆盖统计

Source 窗口自带覆盖统计。在 Source 窗口中查看 beh_sram 的覆盖统计:

  • 在 Files 窗口双击 beh_sram.v,在 Source 窗口打开源代码视图。
  • 滚动 Source 窗口,看到 Figure 13-10 所示的代码。

Source 窗口中的覆盖统计(Figure 13-10):

38
39always @ (negedge clk)
40if (rd_ || wr_) begin
41if (!rd)
42dat_r /test_sm/sram_0/rd;
43if (!wr_1
44mem[addr] <= m_dly dat;
45end
46else
47if ((rd_ || wr_) == 0)
48stime, , “Error: Simultaneous Reads & Writes no
49

Source 窗口包含 Hits 和 BC 两列,分别显示语句命中数和分支覆盖。Figure 13-10 中鼠标悬停在 41 行代码上,这会使 Hits 和 BC 列的覆盖图标变为覆盖数字。Table 13-2 是各种覆盖图标的说明。

Table 13-2 Source 窗口中的覆盖图标:

图标含义
绿色对勾该语句已执行
绿色 E该行已被排除出代码覆盖统计
红色 XHits 列的 X 表示漏测(未执行)的语句(XS)、分支(XB)或条件(XC);BC 列的 X 表示漏测的 true(XT)或 false(XF)分支
  • 选 Tools > Code Coverage > Show coverage numbers。

    Hits 和 BC 列的覆盖图标被替换为每行的执行次数。红色数字表示该行存在漏覆盖;一行上有多个语句时显示省略号(…)。

C:/Tutorial/examples/tutorials/verilog/coverage/beh_sram.v (/test_sm/sram_0) - by file - Default
Hits BC Ln#
7499 38
7499 37498t 1f 39
7498 9372t 28126f 40
9372 41
7498 9376t 28122f 42
9376 43
44
45
46
47
1 0 48
0 49
always @ (negedge clk)
if (rd_ || wr_) begin
if (!rd_)
    dat_r <= #M_DLY mem[addr];
if (!wr_)
    mem[addr] <= #M_DLY dat;
end
else
if ((rd_ || wr_) == 0)
$display($stime, "Error: Simultaneous Reads & Writes no
  • 再选一次 Tools > Code Coverage > Show coverage numbers,取消勾选,回到图标显示。

读懂「行号错觉」

Source 窗口里红色 X 或红色数字只说明「这段代码没被执行过」,不一定是 bug——也可能是测试激励根本没覆盖到这条路径(比如上例 48 行的同时读写错误提示)。先补激励、再排代码,不要看到 X 就改 RTL。

Objects 窗口中的翻转统计

翻转(Toggle)覆盖统计每个逻辑节点从一个状态跳到另一个状态的次数。本章前面通过给 vlog、vcom 或 vopt 命令加 -cover x 参数启用了六态翻转覆盖。更多信息见 User’s Manual 的 Toggle Coverage。

在 Objects 窗口查看翻转数据:

  • 在 Structure (sim) 窗口选中 test_sm。
  • 若 Objects 窗口未打开,选 View > Objects。向右滚动查看各翻转覆盖列(Figure 13-12),或解除停靠并拉大窗口直到所有列都显示。若看不到翻转覆盖列,右键列标题栏,弹出菜单选 Show All Columns。

Objects 窗口中的翻转覆盖列示例:

Z->1Hnodestoggled% Toggled% 01Now
0321134.38%34.38%11.46%0%
032618.75%21.88%7.292%0%
011100%100%33.33%0%
011100%100%33.33%0%
032618.75%21.88%7.292%0%
832618.75%21.88%47.92%…4%
010440%40%13.33%0%
03200%0%0%0%
03200%0%0%0%
011100%100%33.33%0%
011100%100%33.33%0%

把代码行和文件排除出覆盖统计

Questa SIM 允许把某些行和文件排除出代码覆盖统计。可以用 GUI 菜单、名为「exclusion filter file」的文本文件、源代码中的「pragma」,或 coverage exclude 命令来设置排除。pragma 是指示 Questa SIM 忽略括起代码覆盖统计的语句。排除过滤文件和 pragma 的细节见 User’s Manual 的 Coverage Exclusions。

  1. 在 Code Coverage Analysis 窗口的 Statement Analysis 视图中排除某一行:
    • 把 Analysis Type 改为 Statement。
    • 在 Statement Analysis 视图右键某行,弹出菜单选 Exclude Selection(也可以选 Exclude Selection For Instance <inst_name>,只为当前实例排除该选择)。
  2. 取消对已排除语句的排除:右键上一步排除的行,选 Cancel Selected Exclusions。
  3. 排除整个文件:
    • 在 Files 窗口找到 beh_sram.v 文件(VHDL 示例为 beh_sram.vhd)。
    • 右键文件名,选 Code Coverage > Exclude Selected File(Figure 13-13)。

通过 GUI 菜单排除文件

  • 取消所有文件排除:在 Files 窗口任意处右键,弹出菜单选 Code Coverage > Cancel File Exclusions。

生成代码覆盖报告

可以用 GUI 菜单或在 Transcript 窗口输入命令,生成文本或 HTML 格式的覆盖统计报告;也可以用菜单生成覆盖排除的文本报告。

用 GUI 菜单生成文本覆盖报告,二选一:

  • 在主窗口菜单栏选 Tools > Coverage Report > Text。
  • 在 sim 或 Files 窗口右键任意对象,弹出菜单选 Code Coverage > Code Coverage Reports。

在 Instance Coverage 窗口右键任意对象,弹出菜单选 Code coverage reports;Instance Coverage 窗口激活时也可在主窗口菜单栏选 Instance Coverage > Code coverage reports。

这会打开 Coverage Text Report 对话框(Figure 13-14),可以选择报告:所有文件、所有实例、所有设计单元、指定设计单元、指定实例或指定源文件。

Coverage Text Report 对话框

Questa SIM 会在当前目录创建报告文件(默认名 report.txt),并立即在产品自带的 Notepad 文本查看器/编辑器中显示。「open in」栏允许你改为在 Source viewer 中显示报告,或在用 EDITOR 环境变量指定的编辑器中显示。见 User’s Manual 的 Setting Environment Variables。

生成 HTML 覆盖报告:在主窗口菜单栏选 Tools > Coverage Report > HTML,打开 Coverage HTML Report 对话框,指定 HTML 报告的输出目录路径即可。

Coverage HTML Report 对话框

HTML 覆盖报告提供浏览器中的动态覆盖视图(Figure 13-16)。HTML Coverage Summary 页面包含一个「List of Design Units included in report…」超链接,点击后跳转到一张表,列出设计中所有设计单元及各覆盖类型的覆盖百分比;这张表可按总覆盖或任一覆盖类型排序。

HTML 覆盖报告示例(Figure 13-16):

Number of tests run:1
Passed:1
Warning:0
Error:0
Fatal:0

按结构汇总(Coverage Summary by Structure):

Design ScopeCoverage
test sm61.33%
nop100.00%
ctrl0.00%
wt wd100.00%
wt blk100.00%
rd wd100.00%
ill op100.00%
sm seq073.72%
sram 050.37%

按类型汇总(Coverage Summary by Type):

Coverage TypeBinsHitsMissesWeight% HitCoverage
Statements12411212190.32%90.32%
Branches42375188.09%88.09%
FEC Expressions111101100.00%100.00%
FEC Conditions20210.00%0.00%
Toggles20942961798114.13%14.13%
FSMs31229170.96%75.45%
States11101190.90%90.90%
Transitions20128160.00%60.00%

默认情况下 coverage report 命令生成文本文件,加 -html 参数才生成 HTML。用 notepad <filename> 命令可以在产品自带的 Notepad 查看器/编辑器中显示文本报告。

生成覆盖排除报告:在主窗口菜单栏选 Tools > Coverage Report > Exclusions,打开 Coverage Exclusions Report 对话框,可选择只显示 pragma 排除、只显示用户自定义排除、或两者都显示。

Coverage Exclusions Report 对话框

本课收尾

本章到此结束。继续之前需要结束当前仿真,在 VSIM> 提示符输入:

quit -sim

自测