相关阅读
Simens EDAhttps://blog.csdn.net/weixin_45791458/category_13125676.html
本文的目的是教会读者如何使用Modelsim/QuestaSim观察一个时间片(Time Slot)中Simulation/Delta Cycle发生的事件,有关Verilog/SystemVerilog中的时序调度的更详细信息,可以阅读Verilog/SystemVerilog Standard中的Scheduling semantics一章,其中详细给出了层次事件队列的定义。
对于Modelsim/QuestaSim,Simulation/Delta Cycle是一个抽象概念,指的是一个持续时间比仿真时间精度还小的循环,每个循环执行所有被触发的进程(进程指的是always语句、initial语句、assign语句等),在所有被触发的进程结束/挂起后,进入下一个Simulation/Delta Cycle,并执行那些在上一个循环执行的进程中被触发的进程,直到当前仿真时间不存在活跃事件。
下面用一个愚蠢的例子进行说明,注意:一定不要在设计中使用这种风格的代码。
// 例1 // a, b, c的值最终是多少? module demo; reg a = 0; reg b = 0; reg c = 0; initial begin #4 a = 1; b = 1; end initial @(b) begin a = 0; c = 1; end initial @(negedge a) begin b = 0; end initial @(posedge c) begin c = 0; end endmodule在仿真时间0,变量a、b、c的赋值在一个Simulation/Delta Cycle中先后执行,它们被给予了初值0;在仿真时间4,变量a、b在第一个Simulation/Delta Cycle中先后被赋值为1,其中变量b赋值后触发了initial @(b),该进程中的语句将在第二个Simulation/Delta Cycle中执行;在仿真时间4,变量a在第二个Simulation/Delta Cycle中被赋值为0,触发了initial @(negedge a),随后变量c在第二个Simulation/Delta Cycle中被赋值为1,触发了initial @(posedge c),这两个进程中的语句将在第三个Simulation/Delta Cycle中执行;在仿真时间4,变量b在第三个Simulation/Delta Cycle中被赋值为0,变量c在第三个Simulation/Delta Cycle中被赋值为0,需要注意的是,这两个赋值的先后顺序是不确定的(即未定义行为),即使initial @(negedge a)先被触发,更详细信息可以参考下面的博客。
Verilog基础:时序调度中的竞争(一)(不要在两个及以上的always或initial结构中对同一个变量赋值)https://blog.csdn.net/weixin_45791458/article/details/134606846?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522ea312df4d330b6ccc7f1d81970a4e309%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=ea312df4d330b6ccc7f1d81970a4e309&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-4-134606846-null-null.nonecase&utm_term=%E7%AB%9E%E4%BA%89&spm=1018.2226.3001.4450下面我们将使用Modelsim展示如何在波形窗口观察到这些信息,首先按照正常的流程进行编译和仿真,结果如图1所示。
图1 仿真结果
从图1中可以看出,变量a、b、c的值似乎一直是0,但在仿真时间4时出现了一个类似毛刺的变化。
为了观察这个毛刺的具体情况,我们需要使用图2所示的Wave Expand Time Toolbar。
图2 Wave Expand Time Toolbar
其中各按钮的功能如表1所示。
表1
| 按钮 | 名字 | 功能 |
| Expanded Time Off | 默认模式 | |
| Expanded Time Deltas Mode | 进入Delta时间模式 | |
| Expanded Time Events Mode | 进入Event时间模式 | |
| Expand All Time | 展开所有时间(只有在非默认模式下可用) | |
| Expand Time at Active Cursor | 展开标尺处的时间(只有在非默认模式下可用) | |
| Collapse All Time | 折叠所有时间(只有在非默认模式下可用) | |
| Collapse Time at Active Cursor | 折叠标尺处的时间(只有在非默认模式下可用) |
点击按钮进入Delta时间模式,此时的波形如图3所示。
图3 仿真结果
从图2中可以看出,变量a、b、c的值似乎一直是0,但在仿真时间4时出现了一个红点,这代表信号在该仿真时间的Simulation/Delta Cycle中变化了多次。
点击按钮展开所有时间,此时的波形如图4所示。
图4 仿真结果
从图3中可以看出,被展开区域的背景变成了蓝色,此时底部的仿真时间4后出现了+1,+2等标志,这代表了Delta时间或者说Simulation/Delta Cycle,可以看出其中有三个Simulation/Delta Cycle,信号的变化和之前的分析一致。
虽然Delta时间可以反映信号在同一仿真时间的多次变化,但每个Simulation/Delta Cycle依然有多个信号变化,例如第一个Simulation/Delta Cycle,信号a、b变化;第二个Simulation/Delta Cycle,信号a、c变化;第三个Simulation/Delta Cycle,信号b、c变化。
如果想获得更详细的信号变化情况,可以使用按钮,此时的波形如图5所示。
图5 仿真结果
从图4中可以看出,被展开区域的背景变成了绿色,此时底部的仿真时间4后出现了+1,+2等标志,这代表了Event时间,可以看出其中有六个时间,每个时间只有一个信号变化,可以看到在最后的第三个Simulation/Delta Cycle中,Modelsim选择先对变量b赋值,后对变量c赋值,再次强调,赋值顺序是不确定的(即未定义行为)。
除了波形窗口,在信号列表中也可以观察到Delta时间和Event时间的具体情况,如图6和图7所示(可以通过configure list -delta命令切换两种模式)。
图6 信号列表
图7 信号列表
使用单步运行功能也可以观察到语句执行的具体情况,在此不进行详细说明。
某些情况下,可能用户在观察Delta时间和Event时间时会有意想不到的结果,下面用一个例子进行说明。
// 例2 module demo; reg a = 0; initial begin #4 a = 1; a = 0; end endmodule默认情况下的仿真结果如图8所示。
图8 仿真结果
从图7中并没有看到仿真时间4时期望的毛刺,查看Delta时间和Event时间也看不到信号a变化的过程,这是因为Modelsim在优化过程中直接将重复赋值优化掉了,使用单步运行功能可以强制降低优化等级,此时就可以在仿真结果中看到变量a先被赋值为1,后被赋值为0的过程。
最后需要注意的是,本文中有关Simulation/Delta Cycle的具体定义仅限于Modelsim/QuestaSim,不同的仿真器可能对此有不同的实现方式,下面用一个例子进行说明。
// 例3 always @(q) p = q; always @(q) p2 = not q; always @(p or p2) clk = p and p2; always @(posedge clk)假设存在以上四条always语句,并且变量q、p、clk的初值为0,变量p2的初值为1,当变量q被赋值为1时,按照Modelsim/QuestaSim中的规则,事件的顺序如图9所示。其中数字代表各语句(从上到下编号)或者说一个评估事件(Evaluation event),而<name>(old->new)则代表一个变量的更新事件(Update event)。
图9 Modelsim/QuestaSim中的情况
图9的左列展示了所有执行的语句及其顺序,右列则展示了在这个过程中,由于评估事件而产生的更新事件,以及由更新事件触发的评估事件,可以再次看出,这个过程符合之前的分析,即在当前Simulation/Delta Cycle先处理所有的更新事件,在下一个Simulation/Delta Cycle处理那些被触发的评估事件。
默认情况下的仿真结果如图10所示,Delta时间的仿真结果如图11所示,Event时间的仿真结果如图12所示。
图10 仿真结果
图11 仿真结果
图12 仿真结果
对于其他仿真器,则可能使用其他实现方式,图13展示了其中一种情况。
图13 另一种可能的情况
在图13展示的情况中,仿真器在always @(q) p = q;被触发后就立刻处理了,即使此时always @(q) p2 = not q;已经在事件队列中了,就像是插队一样,这是允许的,Verilog/SystemVerilog Standard并没有强制要求顺序。
笔者尝试使用VCS+Verdi查看例1的波形(这需要使用其中的Expand Delta和Event Sequence功能),但无法观察到细节,只能在交互式仿真调试模式并单步运行才能观察到图14所示的变化。
图14 Verdi中的Event Sequence