资讯动态

Verilog基础:时序调度中的竞争(三)(如果不确定,不要使用#0)

发布时间:2026/10/27 1:13:40 来源:尧图企业网站定制
相关阅读Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482作为一个硬件描述语言Verilog HDL常常需要使用语句描述并行执行的电路但其实在仿真器的底层这些并行执行的语句是有先后顺序的然而Verilog标准并没有将这些事件调度的顺序定死而是给予了仿真器厂商一定的自由去实现自己的产品这就导致了设计者如果不遵循一定的编程习惯会导致意想不到的仿真结果下面是一些相关的规则。如果不确定不要使用#0尽管使用#0延迟可以消除一些竞争情况但如果设计者不是对Verilog的时序调度有充分的了解就不要使用#0延迟这会使时序调度变得复杂难懂。#0延迟将一个事件调度到inactive events region这个region是处于active events region和nonblocking events region之间的所以使用#0可以避免一个事件与当前的活跃事件竞争下面举一个Verilog基础时序调度中的竞争一-CSDN博客中竞争的例子加以说明。//例1 timescale 1ns/1ps module test(); initial $display(The initial_0 execute); initial #0 $display(The initial_1 execute); initial $display(The initial_2 execute); endmodule 输出: The initial_2 execute //前两个输出的顺序是不定的 The initial_0 execute The initial_1 execute //这个输出一定是最后的在上例中三个initial结构同时执行执行顺序是不定的但是#0能保证#0 $display(The initial_1 execute);语句被调度至inactive events region而$display(The initial_0 execute);和$display(The initial_2 execute);仍然被调度至active events region执行所以The initial_1 execute一定最后输出而后面两个输出的顺序仍然是不确定的因为他们都被调度至active events region执行。但如果出现了两个#0则这两个被调度至inactive events region的事件的执行顺序仍然是不确定的如下所示。//例2 timescale 1ns/1ps module test(); initial $display(The initial_0 execute); initial #0 $display(The initial_1 execute); initial #0 $display(The initial_2 execute); endmodule 输出: The initial_0 execute //这个输出一定是最先的 The initial_2 execute //后两个输出的顺序是不定的 The initial_1 execute在其他竞争的例子中使用#0也可以达到相同的效果如下例所示。//例3 timescale 1ns/1ps module test(); reg a, b, c; initial begin #5; a 1; b 1; c 1; end initial (a) $display(The initial_0 execute); initial (b) #0 $display(The initial_1 execute); initial (c) $display(The initial_2 execute); endmodule 输出 The initial_2 execute //前两个输出的顺序是不定的 The initial_0 execute The initial_1 execute //这个输出一定是最后的按照Verilog基础时序调度中的竞争一-CSDN博客中所说被触发的三个always结构的执行顺序是不定的但由于这里有#0导致了#0 $display(The initial_1 execute);被调度到inactive events region执行因此它在其他两个被调度至active events region的语句之后执行。以及前文说过的结构交错的例子他也可以用#0消除竞争如下所示。//例4 timescale 1ns/1ps module test(); reg a; wire b; initial begin #1; a 1; #1; a 0; #0 $display(b is %b, b); end assign b a; endmodule 输出 b is 0在使用了#0延迟后#0 $display(b is %b, b);被调度到inactive events region执行因此在a0执行后首先会去执行位于active events regionassign b a;然后再执行#0 $display(b is %b, b);所以最后显示的结果是确定的0而不会产生不确定。下面的例子显示了#0在并行块中的作用。//例5 timescale 1ns/1ps module test(); initial fork $display(The initial_0 execute); #0 $display(The initial_1 execute); $display(The initial_2 execute); join endmodule 输出 The initial_2 execute //前两个输出得顺序是不定的 The initial_0 execute The initial_1 execute //这个输出一定是最后的并行块本不保证块内语句的执行顺序但有了#0后#0 $display(The initial_1 execute);被调度到inactive events region执行因此它是最后输出的而两个在active events region执行的语句执行顺序不定。但需要注意的是即使#0可以将语句调度至inactive events region执行但它仍然需要遵循串行块的执行顺序原则即一条语句一定在前一条语句执行完后再执行举例如下。//例6 timescale 1ns/1ps module test(); initial begin $display(The initial_0 execute); #0 $display(The initial_1 execute); $display(The initial_2 execute); end endmodule 输出 The initial_0 execute //这三个输出的执行顺序是确定的 The initial_1 execute The initial_2 execute即使$display(The initial_2 execute);是被调度到active events region执行而#0 $display(The initial_1 execute);是被调度到inactive events region执行但由于begin-end块的特性$display(The initial_2 execute);无法在#0 $display(The initial_1 execute);前调度而是需要等待inactive events完成后再进入active events region。而#0的执行需要等待其他initial结构的active events执行完成后才能执行继而$display(The initial_2 execute);再被放入active events region并执行如下例所示。//例7 timescale 1ns/1ps module test(); initial begin $display(The initial_0 execute); #0 $display(The initial_1 execute); $display(The initial_2 execute); end initial begin $display(The initial_3 execute) $display(The initial_4 execute) end endmodule 输出 //前三个输出能保证的是The initial_4 execute在The initial_3 execute后输出 //而且他们三个必须在#0 $display(The initial_1 execute);执行前输出 The initial_0 execute The initial_3 execute The initial_4 execute //下面的语句一定在第四个输出 The initial_1 execute //下面的语句一定在上条语句后(第五个输出) The initial_2 execute可以看到对于#0的使用需要对事件调度有较深的理解而#0是为了消除竞争的因此这只是治标不治本的方法因此最好的方法是避免写出有竞争的语句而不是盲目使用#0这就是本文的标题所说的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑