在学习和使用 Verilog 的过程中,难免会碰到需要深入理解仿真器调度的问题。今天这篇聊聊使用 Verdi 去分析 NBA Delay 的问题。
NBA 就是 NonBlocking Assignment,非阻塞赋值 的缩写。它通常用来描述一个用时钟沿触发的寄存器。在 Verilog 普及早期,人们通常会在 NBA 的<=
之后加个单位延时#1
来解决早期仿真器行为不一致的问题。
所谓习惯成自然,NBA Unit Delay 在某些设计中一直沿用下来,那么如何去理解这个延时的作用呢?SNUG 上的知名作者 Clifford E. Cummings
在 2002 年有篇文章阐述的挺详细,感兴趣的朋友可以搜来研究,不再赘述。
下面给出一些代码片断,同样感兴趣的朋友可以自己完善并用 VCS 仿真生成波形,然后用 Verdi 打开。
首先创建三个时钟,注意两个二分频时钟的创建方式不同。
always #(10/2) clk = ~clk;
always #(20/2) clk_div2_direct = ~clk_div2_direct;
always @ ( posedge clk or negedge rst_n ) begin
if ( ~ rst_n ) begin
clk_div2 <= 1'b0;
end
else begin
clk_div2 <= ~clk_div2;
end
end
然后用 clk 触发一个不停翻转的寄存器 d1,再分别用两个二分频时钟去采样,保存在 d5 和 d6 中。
always @ ( posedge clk or negedge rst_n ) begin
if ( ~ rst_n ) begin
d1 <= 1'b0;
end
else begin
d1 <= ~d1;
end
end
always @ ( posedge clk_div2 or negedge rst_n ) begin
if ( ~ rst_n ) begin
d5 <= 1'b0;
end
else begin
d5 <= d1;
end
end
always @ ( posedge clk_div2_direct or negedge rst_n ) begin
if ( ~ rst_n ) begin
d6 <= 1'b0;
end
else begin
d6 <= d1;
end
end
用 VCS 仿真的时候,加上编译时选项+fsdb+region
和运行时选项+fsdb+delta
。
然后用 Verdi 打开生成的 fsdb 波形。正常的话,可以看到 d5 和 d6 的波形是完全不同的,一个是常0,一个是常1。
只从上图分析的话,两个二分频时钟的波形是完全一致的,被采样的数据是同一个,那么采到的数据也应该是相同的。但我们知道这两个二分频时钟的生成方式是不同的,那么不同在什么地方呢?
在 Verdi 的 nWave 窗口中选中 View - Expand Delta - Region Mode,把 Cursor 移动到二分频时钟的上升沿,然后点击 Expand/Collapse Time at Cursor,简单点的话直接按 w 键。
然后就可以看到这个仿真时刻的 Simulation Region,里面展示了各个 Event 和 Region 的关系。
这个例子中,只存在绿色的 Active Region 和 红色的 NBA Region。在某些 glitch debug 的例子中,还能看到 Re-Active Region 和 Re-NBA Region。
Region 的展示可以帮助我们很好的理解 Verilog 规范中的定义的信号调度。
此外,Verdi 还可以通过点击 Tools - Event Sequence 来显示图形化的 Event 序列。
Verdi 真得是很好很强大。
不过随着工具的逐渐强大,站在工具背后的人呢?是在逐渐退化还是改变了进化方向?欢迎留言说说你的看法。