这一篇在干嘛?

波形窗口只能告诉你「信号什么时候变了」,却说不清「是谁让它变的」。这一篇介绍两个按连通性思考的调试视图:Schematic(增量原理图)窗口和 Dataflow 窗口。你将学会从某个信号出发,逐级展开它的驱动者与读者(drivers/readers),像侦探一样反向追溯一个意外跳变、甚至一个 X(未知态)到底从哪条路径传播而来。示例设计是一个带 cache 模块和处理器读写请求的 test bench,分 Verilog 和 VHDL 两个版本。

Schematic 窗口:增量原理图调试(原文第 9 章)

Schematic 窗口的 Incremental(增量)视图可以按「进程到进程」的方式展开设计的物理连通性,显示某个信号、net、寄存器、进程、模块或 architecture 的驱动者/读者。

编译并加载设计

本课示例文件路径:

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

本课以 Verilog 版本为例,有 VHDL license 的读者可改用 VHDL 版本,操作步骤一致。

  1. 新建一个目录,把 <install_dir>/examples/tutorials/verilog/schematic 下的所有文件复制进去(VHDL 用户复制 vhdl/schematic 目录)。
  2. 启动 Questa SIM 并切换到练习目录:
    • 在 UNIX shell 输入 vsim,或 Windows 下双击 Questa SIM 图标;若弹出 Welcome to Questa SIM 对话框,点 Close。
    • 选择 File > Change Directory,切换到第 1 步建的目录。
  3. 修改 WildcardFilter 设置,在 Questa SIM> 提示符下执行:
set WildcardFilter "Variable Constant Generic Parameter SpecParam Memory Assertion Endpoint ImmediateAssert"

这条命令把默认列表中的「CellInternal」去掉了,让 cell 内部的所有信号也会被仿真器记录,从而在调试环境中可见。

  1. 执行本课 DO 文件:在 Questa SIM> 提示符输入 do run.do。该 DO 文件依次完成:
    • 创建工作库 — vlib work
    • 编译设计文件 — vlogvcom
    • 优化设计 — vopt +acc top -debugdb -o top_opt
    • 加载设计 — vsim -debugdb top_opt
    • 把信号加入 Wave 窗口 — add wave /top/p/*
    • 记录设计中所有信号 — log -r /*
    • 运行仿真 — run -all
  2. 把数值基改为符号制:输入 radix -symbolic 并回车。

FPGA 语境

-debugdb 优化选项保留了调试数据库,这是 Schematic/Dataflow 视图能工作的前提。在安路 TD 这类 FPGA 流程里,如果你习惯给网表加 -O5 之类的高优化等级,调试时记得退回保留可见性的选项,否则内部信号会被优化掉看不到。

探索连通性

  1. 打开 Schematic 窗口:选菜单 View > Schematic,或在 Transcript 窗口的 VSIM 提示符下执行 view schematic。窗口打开后默认处于 Incremental 视图。
  2. 向 Schematic 窗口添加一个信号:
    • 确认 Structure (sim) 窗口中选中了实例 initial69
    • 把 strb 信号从 Objects 窗口拖到 Schematic 窗口(Figure 9-2)。

Schematic 窗口中的 strb 信号

增量视图以橙色高亮显示 strb 信号。鼠标悬停在任何设计对象上都会弹出 tooltip 信息框,图中展示的是 initial69 模块(青色方框)的详情。每个信号 net 两端会显示当前值;Schematic 窗口获得焦点时,按键盘上的 v 键可以开关信号值显示。

  1. 查找 p 模块内部 strb 信号的读者:
    • 在 p 模块内右键高亮的 strb 信号,选 Expand Net To > Readers(Figure 9-3)。

Expand Net to  width= Readers 菜单"/>

p 模块展开后的样子

  1. 查找 p 模块外部 strb 信号的读者。鼠标悬停到信号 pin 上时,光标会变成右箭头、左箭头或双向箭头:右箭头表示双击可展开到读者(fanout),左箭头表示双击可展开到驱动者,双向箭头则同时展开两者。

鼠标悬停信号 pin 的光标形态

  • 如图 9-5 所示,把光标移到 strb 信号上看到右箭头后双击。

右箭头表示展开到读者

  • 所有读者随即被「长」出来(Figure 9-6)。

strb 信号的所有读者被展开

  1. 查找 p 模块中 NAND 门上 test 信号的驱动者:
    • 点击 Show Wave 按钮,打开 Schematic 窗口内嵌的 Wave 查看器(窗口太小时可先拉大)。
    • 在原理图中选中 NAND 门,该门输入输出信号的波形会载入 Wave 查看器,门本身高亮。

选中 NAND 门后波形载入内嵌查看器

  • 在 Wave 查看器中选中 test 信号,原理图中对应的 test 输入随之高亮(Figure 9-7)。

选中 test 信号

注意:内嵌 Wave 查看器激活时窗口标题是「Schematic -Default (wave)」,增量视图激活时是「Schematic -Default (schematic)」。

  • 在原理图中点击高亮信号 test 的 pin,让原理图视图重新激活。
  • 点击 Expand net to all drivers 图标。
  • 从 Figure 9-8 可以看到,test 信号的驱动进程是 p 模块内的一个 i0 模块。

test 网展开显示全部驱动者

  1. 展开 c 模块中进程 always155(VHDL 版本标为 line_84)上信号 oen 的读者:
    • 点击 oen 的 pin 使其激活。
    • 在原理图任意处右键弹出菜单,选 Expand Net To > Readers,结果见 Figure 9-9。

oen 信号展开到读者

oen 展开到读者时停在 s0–s3 实例的边界上。想看实例内部,双击实例内的 oen net,会「长」出一个三态器件(Figure 9-10)。

在 s0 实例内长出 oen 的三态器件

  1. 继续用上面任一方式探索设计:双击信号 pin 或 net、使用工具栏按钮、或用右键弹出菜单。
  2. 如果 net 两端的信号值叠在一起看不清(Figure 9-11):

信号值重叠难以分辨

  1. 点击 Regenerate 按钮重绘原理图,所有设计元素、信号值和 pin 名会清晰显示(Figure 9-12):
clkSt0->St1St0->St1clk
St1 pstrbSt1St1pstrb
prwSt1St1prw
  1. 结束时,按住 Delete Content 按钮不放,直到弹出菜单:

Delete Content 按钮的弹出菜单

  1. 点击 Show Wave 按钮

Show Wave 按钮

关闭内嵌 Wave 查看器。

从原理图查看源代码

Schematic 窗口可以显示任何设计对象的源代码预览。

  1. 向 Schematic 窗口添加一个信号:
    • 确认 Structure (sim) 窗口选中实例 p。
    • 把 t_out 信号从 Objects 窗口拖到 Schematic 窗口。
    • 双击 NAND 门,会弹出 Code Preview 窗口(Figure 9-13),所选对象的源代码被高亮。

Code Preview 窗口

Code Preview 窗口提供四键工具栏:在 Source Editor 中打开源码;把选中的代码重新居中显示;复制选中代码;在窗口底部打开 Find 工具栏搜索代码。

  • 试着把几个工具栏按钮都点一遍。
  1. 结束时关闭 Code Preview 窗口,然后按住 Delete Content 按钮直到弹出菜单出现,选 Delete All 清空原理图视图。

折叠与展开实例

复杂实例的内容在增量视图中默认折叠(隐藏),以节省屏幕空间、提高可读性。

  1. 显示一个折叠实例:
    • 在 Structure 窗口展开 c 模块的层次。
    • 把 c 模块中的 s2 实例从 Structure 窗口拖到 Schematic。

折叠状态的实例

折叠实例由带虚线边框的深蓝色方块表示(Figure 9-14);鼠标悬停时 tooltip 会显示 FOLDED

  1. 展开这个折叠实例:
    • 在折叠实例内部右键打开弹出菜单。
    • 选择 Fold/Unfold,实例展开为 Figure 9-15。

展开后的实例

因为我们只是把它拖进增量视图、并没有把任何信号追踪到它内部,所以此时看不到 s2 的内容。

  1. 显示 s2 实例的内容:双击 s2 内部的 addr net,相连的门和内部实例就会出现(Figure 9-16)。

s2 展开后显示内部内容

  1. 重新折叠 s2:
    • 左键点击 s2 实例边框使其高亮。
    • 右键打开弹出菜单,选 Fold/Unfold 折叠实例。

s2 重新折叠

  1. 试试其他折叠实例(s0、s1、s3)。结束后用 Delete Content 按钮清空原理图。

追踪事件

Schematic 窗口可以把事件追溯到它的起因。在增量视图任意处右键,选 Event Traceback 即可打开相关选项(Figure 9-18)。

Event Traceback 菜单选项

事件追踪从当前「active time」开始,该时间由以下三者之一决定:Wave 窗口中选中的光标、Schematic 窗口内嵌 Wave 查看器中选中的光标、或 Schematic 窗口的 Current Time 标签。

打开 Current Time 标签

本例使用内嵌 Wave 查看器光标设定的时间。Current Time 标签默认打开,以下步骤用于在增量视图中开关它:

  1. 增量视图激活时,选 Schematic > Preferences 打开 Incremental Schematic Options 对话框。
  2. 在 Show 区勾选 Current Time label,点 OK 关闭对话框。

勾选 Current Time 标签显示选项

Current Time 标签出现在增量视图右上角。

增量视图中的 Current Time 标签

追踪一个事件

  1. 向原理图添加对象:
    • 确认 Structure (sim) 窗口选中实例 p。
    • 把 t_out 信号从 Objects 窗口拖到原理图窗口。
  2. 打开 Schematic 窗口的 Wave 查看器:点击工具栏的 Show Wave 按钮。
  3. 在内嵌 Wave 查看器中显示某进程的信号:在原理图中选中 NAND 门,其输入输出波形即载入 Wave 查看器。
  4. 在 Wave 查看器中放一个光标指定 Current Time:
    • 把光标拖到 Wave 查看器中 strb 波形 465 ns 处的跳变上。
    • 在 Wave 查看器中选中 strb 的信号路径,原理图中 strb net 随之高亮(Figure 9-21)。

内嵌 Wave 查看器

原理图右上角的 Current Time 标签此时显示光标所在时间 465 ns。 5. 追溯事件的起因:

  • 在原理图中右键高亮信号打开弹出菜单。
  • 选择 Event Traceback > Show Cause,会打开一个 Source 窗口,直接驱动进程被高亮(Figure 9-22)。
C:/Tutorial/examples/tutorials/verilog/schematic/top.v (/top) - Default
Ln# 1/2 Driver Lines
wire [15:0] sdata;
initial begin
clk = 1'b0;
end
always #20 clk = ~clk;

同时 Transcript 窗口显示追踪结果(Figure 9-23):

find drivers -source -time {465 ns} -cause /top/p/strb
# Multiple active drivers exist at time 460 ns for signal sim:/top/p/strb:
# PROCESS: #ALWAYS#29 SIGNAL: /top/clk FILE: top.v:29
# PROCESS: #INITIAL#25 SIGNAL: FILE: top.v:26
#
# ----
# *PARTIAL* causality trace results for signal "sim:/top/p/strb":
#
# Time | Type | Scope | Signal | Source File
# ---- | ---- | ---- | ---- | ----
# 460 ns | Gate | /top/p | strb_r | proc.v:25
# 460 ns | PROCESS | /top/p | clk | proc.v:69
# 460 ns | Gate | /top | clk | top.v:29
  • 想看路径细节:按住 Event Traceback 工具栏按钮不放,弹出菜单出现后选 View Path Details,打开 Active Driver Path Details 窗口。它显示导致所选事件的时序进程信息:信号名、因果路径上每个进程的时间、以及因果进程在代码中的位置。

Active Driver Path Details 窗口

  1. 在 Schematic 窗口中查看 assign251 进程上 strb_r 的路径细节:
    • 点击 Active Driver Path Details 窗口顶行,选中 strb_r 的驱动者。
    • 点击对话框 View Path Details 区的 Schematic Window 按钮(Figure 9-25)。

Schematic Window 按钮

这会打开一个专属的 Schematic (Path Details) 窗口,显示所选驱动者的路径细节(Figure 9-26)。其 Wave 查看器区还会显示 Trace Begin 和 Trace End 两个光标。

Schematic Path Details 窗口

可以继续用同样方式追踪其他事件、在专属 Schematic 和 Wave 窗口中查看路径细节。 7. 继续之前清空 Schematic 窗口:

  • 关闭 Active Driver Path Details 窗口。
  • 关闭 Schematic (Path Details) 窗口。
  • 点击 Schematic 标签切回原 Schematic 窗口。
  • 用 Delete Content 按钮清空 Schematic Viewer。
  • 点击 Show Wave 图标关闭原理图窗口的 Wave 视图。

本课收尾

  1. 在 VSIM> 提示符输入:
quit -sim

把 WildcardFilter 恢复出厂默认:

set WildcardFilter "default"

Dataflow 窗口调试(原文第 10 章)

Dataflow 窗口同样用于探索设计的「物理」连通性、追踪在设计中传播的事件、找出意外输出的原因。窗口中显示进程、信号/net/寄存器以及互连关系。

编译并加载设计

本课示例文件路径:

  • Verilog – <install_dir>/examples/tutorials/verilog/dataflow
  • VHDL – <install_dir>/examples/tutorials/vhdl/dataflow
  1. 新建目录,把 <install_dir>/examples/tutorials/verilog/dataflow 下所有文件复制进去(VHDL 用户复制 vhdl/dataflow 目录)。
  2. 启动 Questa SIM 并切换目录:
    • UNIX shell 输入 vsim,或 Windows 下点 Questa SIM 图标;欢迎对话框出现则点 Close。
    • 选 File > Change Directory 切到练习目录。
  3. 修改 WildcardFilter 设置:
set WildcardFilter "Variable Constant Generic Parameter SpecParam Memory Assertion Endpoint ImmediateAssert"

同样是去掉默认列表中的「CellInternal」,让 cell 内所有信号被记录、在调试环境中可见。 4. 执行 DO 文件:在 Questa SIM> 提示符输入 do run.do。它依次:创建工作库、编译设计文件、优化设计、加载设计、把信号加入 Wave 窗口、记录设计中所有信号、运行仿真。 5. 打开 Dataflow 窗口:在 VSIM> 提示符输入 view dataflow 并回车。 6. 改基为符号制:在 VSIM> 提示符输入 radix -symbolic

探索连通性

  1. 向 Dataflow 窗口添加信号:
    • 确认 Structure (sim) 窗口选中实例 p。
    • 把 strb 信号从 Objects 窗口拖到 Dataflow 窗口(Figure 10-1)。

Dataflow 窗口中的 strb 信号

  1. 探索设计:
    • 点击 Expand net to all readers 图标。

Expand net to all readers 图标

视图展开,显示与 strb 相连的进程(Figure 10-2)。

展开显示与 strb 相连的进程

  • 查找进程 nand50(VHDL 版本标为 line_71)上 test 信号的驱动者: i. 点击 Show Wave 图标打开 Wave 查看器(必要时拉大 Dataflow 窗口)。 ii. 在 Dataflow 查看器中选中 nand50 门(VHDL 版本标为 t_out_asgn),其输入输出波形载入 Wave 查看器,门高亮。 iii. 在 Wave 查看器中选中 test 信号,Dataflow 查看器中 test 输入随之高亮(Figure 10-3)。

选中 test 信号

 iv. 在 Dataflow 查看器中选中该高亮信号(使 Dataflow 窗口的这一部分激活),然后点击 Expand net to all drivers 图标。

Figure 10-4 中绿色高亮标出你在设计中走过的路径。

test 网展开显示全部驱动者

  • 选中进程 always155(VHDL 版本标为 line_84)上 oen 信号的 net,点击 Expand net to all readers 图标。

oen 网展开显示全部读者

想继续探索随意。结束时按住 Delete Content 按钮不放,出现下拉列表后选 Delete All 清空 Dataflow 查看器。

追踪事件

另一个实用功能是追踪造成意外输出值的事件。借助 Dataflow 窗口的内嵌 Wave 查看器,可以从一次跳变反向追溯到导致该意外输出的进程或信号。

  1. 设置默认行为:在 Wave 窗口双击信号时在 Dataflow 窗口显示驱动者。
    • 点击 Wave 窗口标签使其激活。
    • 选 Wave > Wave Preferences,打开 Wave Window Preferences 对话框。
    • 在「Double-click will:」菜单中选 Show Drivers in Dataflow,点 OK(Figure 10-6)。

Wave Window Preferences 对话框

  1. 向 Dataflow 窗口添加对象:
    • 在 Wave 窗口中双击 t_out 波形任意处。Source 窗口会打开并显示该信号的源代码。
    • 点击 Dataflow 标签打开 Dataflow 窗口。
    • 若尚未打开,点击 Show Wave 图标打开 Wave 查看器(必要时拉大窗口)。
    • 点击 nand50 门,在 Wave 查看器中显示其输入输出(Figure 10-7)。

内嵌 Wave 查看器

  1. 追踪 NAND 门的输入:
    • 在 Dataflow 查看器中双击进程 nand50(VHDL 版本标为 line_71)。显示跳到 proc.v 的源代码视图,蓝色箭头指向 NAND 门的声明处(Figure 10-8)。
C:/Tutorial/examples/tutorials/verilog/dataflow/proc.v (/top/p) - Default
Ln#
49 nor (test2, _rw, test_in);
50 nand (t_out, test, strb);
51
52 task write;
53 input [`addr_size-1:0] a;
54 input [`word_size-1:0] d;
55 begin
56 if (verbose) $display("%t: Writing data=%h to addr=%h", $time
57 addr_r = a;
  • 点击 Dataflow 标签回到 Dataflow 窗口。
  • 在 Wave 查看器中滚动到 t_out 的最后一次跳变。
  • 点击 t_out 最后一次跳变的右侧,光标会吸附到 2785 ns(Figure 10-9)。

信号被自动加入 Wave 查看器

  • Dataflow 查看器中 t_out 应为红色高亮。点击该高亮信号使其激活,然后选 Tools > Trace > Trace next event 追踪第一个相关事件。

Questa SIM 会在 Wave 查看器加一个光标,标出最后一个事件——2745 ns 处 strobe 跳到 St0——正是它使 t_out 输出 St1(Figure 10-10)。

光标在 Wave 查看器中标记最后一个事件

  • 再选两次 Tools > Trace > Trace next event,观察光标跳到下一个事件。
  • 选择 Tools > Trace > Trace event set。

Dataflow 流程图长出前一级进程,显示 strb 信号的输入驱动者(Figure 10-11)。同时 Wave 查看器也会显示新选中进程的输入输出信号。

追踪事件集

可以照此方式继续在设计中追踪事件:反复选 Trace next event 直到 Wave 查看器中出现你感兴趣的跳变,再选 Trace event set 更新 Dataflow 流程图。

  1. 结束时选 File > Close Window 关闭 Dataflow 窗口。

追踪 X(未知态)

Dataflow 窗口可以轻松追踪未知值(X)在设计中传播的过程。它与 Wave 窗口动态联动:先在 Wave 窗口看信号,再用 Dataflow 窗口追问题的源头;在 Dataflow 中遍历时,相关信号会自动加进 Wave 窗口。

  1. 在 Wave 和 Dataflow 窗口中查看 t_out:

    • 在 Wave 窗口滚动到能看到 /top/p/t_out。

    t_out 在 2066 ns 变为未知态 StX,之后一直 1 与未知之间来回跳(Figure 10-12)。波形的红色表示未知值。

带未知值的信号

双击波形后源代码视图再次打开并指向 t_out;同时会自动打开一个 Dataflow 窗口,显示 t_out、相关进程和它的波形。

  • 点击 Dataflow 标签激活 Dataflow 窗口。

因为上次关闭窗口时 Wave 查看器是打开的,它会再次在 Dataflow 窗口内打开,且 t_out 处于高亮(Figure 10-13)。

带 Wave 查看器的 Dataflow 窗口

  • 把光标放在 t_out 为未知的时间上(例如 2728 ns)。
  1. 追踪未知态:

    • 在 Dataflow 查看器中点击高亮信号使查看器激活(激活后查看器四周出现黑框;信号被选中时呈橙色)。
    • 选菜单 Tools > Trace > ChaseX。

    设计展开,显示 t_out 未知态的来源(Figure 10-14):本例中输入信号 test_in 为 HiZ 值(VHDL 版本为 U)、输入信号 _rw(VHDL 版本为 bar_rw)为 St0,使 test2 输出解算为未知态(StX),未知态再传播到 t_out。

ChaseX 找出 t_out 未知态的成因

FPGA 语境

X 态传播是 FPGA 仿真里最常见的「玄学问题」来源:安路 TD 综合后的寄存器没有复位初值、或异步复位未覆盖全部寄存器时,上电仿真经常满屏 X。学会用 ChaseX 反向追到第一个产生 X 的源头(往往是未复位的寄存器或未驱动的输入),比盯着波形猜要高效得多。

  1. 继续之前清空 Dataflow 窗口:
    • 点击 Delete All 图标清空 Dataflow 查看器。
    • 点击 Show Wave 图标关闭 Dataflow 窗口的 Wave 视图。

在 Dataflow 窗口显示层次

可以用层次实例的方式在 Dataflow 窗口中显示连通性——前提是在添加对象之前先改好选项。

  1. 修改选项以显示层次:
    • 在主窗口菜单选 Dataflow > Dataflow Preferences > Options(窗口未停靠时,在 Dataflow 窗口菜单栏选 Tools > Options),打开 Dataflow Options 对话框(Figure 10-15)。

Dataflow Options 对话框

  • 选 Show: Hierarchy,点 OK。
  1. 向 Dataflow 窗口添加信号 t_out:在 VSIM> 提示符输入:
add dataflow /top/p/t_out

Dataflow 窗口会显示 t_out 及所有层次实例(Figure 10-16)。

Dataflow 窗口中的层次显示

本课收尾

  1. 在 VSIM> 提示符输入:
quit -sim

恢复 WildcardFilter 出厂默认:

set WildcardFilter "default"

自测