相关阅读SystemVerilog基础https://blog.csdn.net/weixin_45791458/category_12517449.html?spm1001.2014.3001.5482有关Verilog中顺序块和并行块的相关内容已经在之前的Verilog基础的文章讲过如下所示。Verilog基础块语句https://blog.csdn.net/weixin_45791458/article/details/132561861?spm1001.2014.3001.5502但在SystemVerilog中并行块除了fork-join这种形式之外还多出了两个变种fork-join_any和fork-join_none本文将对此进行讨论。下面是Verilog中并行块语法的BNF范式有关BNF范式相关内容可以之前的文章。Verilog基础巴科斯范式(BNF)https://blog.csdn.net/weixin_45791458/article/details/132567389?spm1001.2014.3001.5502下面是SystemVerilog中并行块语法的BNF范式可以看到其中变动较大的就是并行块结尾的关键词可以是join、join_any、join_none之间的任何一个。SystemVerilog中的并行块具有以下几个性质1、块内的语句在进入并行块后同时执行同时执行不代表连续执行并行块执行过程中可能会发生进程挂起与切换这点在之后说明。2、块内各语句的过程赋值延迟全部是相对于进入并行块时而言的有关过程赋值延迟的内容可以看Verilog基础延时模型。3、块内各语句的过程赋值延迟可以提供语句赋值的时间顺序。4、根据join keyword关键词的不同控制流可能以不同的方式传出并行块这与Verilog中的并行块不一样。首先回顾一下Verilog中的并行块在并行块开始执行时块内语句同时执行这个同时不是严格意义的同时指的是同一个仿真时间在被调度到仿真时间最后的语句执行完后则并行块整体执行完毕。下面的代码片是一个例子显示了并行块语句的执行情况。//例1 timescale 1ns/1ns initial begin #2 $display(Enter fork at %t, $time); fork #1 $display(Statement1 execute at %t, $time); #2 $display(Statement2 execute at %t, $time); #3 $display(Statement3 execute at %t, $time); join $display(Exit fork at %t, $time); end 输出 Enter fork at 2 Statement1 execute at 3 Statement2 execute at 4 Statement3 execute at 5 Exit fork at 5但是要注意的是对于有内嵌延迟的过程赋值语句一旦右端的表达式的值计算完毕即视作此表达式执行完毕详细请看下面的例子。//例2 reg [1:0]a; initial begin #2 $display(Enter fork at %t, $time); $monitor(a %d at %t, a, $time); fork a #1 1; a #2 2; a #3 3; join $display(Exit fork at %t, $time); end 输出 Enter fork at 2 Exit fork at 2 a x at 2 a 1 at 3 a 2 at 4 a 3 at 5可以看到进入并行块和退出并行块的仿真时间是相同的因为非阻塞赋值的内嵌延迟并不会阻塞控制流执行并行块内的其他非阻塞赋值语句而真正的赋值需要等到3、4、5ns时。将上例中的非阻塞赋值改为阻塞赋值后会发生什么下面给出了这种情况下的输出。//例3 reg [1:0]a; initial begin #2 $display(Enter fork at %t, $time); $monitor(a %d at %t, a, $time); fork a #1 1; a #2 2; a #3 3; join $display(Exit fork at %t, $time); end 输出 Enter fork at 2 a x at 2 a 1 at 3 a 2 at 4 Exit fork at 5 a 3 at 5尽管并行块内各个阻塞赋值语句在同一仿真时间的执行顺序不同但有内嵌延迟的阻塞赋值必须等待延迟时间后才视为执行完毕三条阻塞赋值语句同时执行则延迟最长的那条阻塞赋值语句执行完毕后退出并行块即235ns时退出并行块。对于fork-join的讨论到此为止下面是对于fork-any的讨论。当并行块末尾关键词使用fork-any时当并行块中有任意一条语句执行完毕控制便可以跳出并行块执行之后的语句当然对于并行块中其他尚未执行的语句它们仍然会在被调度的仿真时间执行下面举例说明。//例4 reg [1:0]a; initial begin #2 $display(Enter fork at %t, $time); $monitor(a %d at %t, a, $time); fork #1 a 1; #2 a 2; #3 a 3; join_any $display(Exit fork at %t, $time); end 输出 Enter fork at 2 a x at 2 Exit fork at 3 a 1 at 3 a 2 at 4 a 3 at 5可以看到如果fork-join_any块中的任何一个语句执行完毕控制就可以跳出并行块了即在3ns时就退出并行块了但并行块内部的后两个赋值仍然会在其被调度的时间执行所以在4ns和5ns时a的值发生了改变。这样就会出现一种问题当fork-join块内的语句和块后的语句被调度到同一时间执行时它们的执行顺序有保证吗我们知道begin end块能保证顺序块内语句依次执行但fork-join_any块使得在结束一个并行块前可以执行后面的语句下面看一个例子。//例5 reg [1:0]a; initial begin #2 $display(Enter fork at %t, $time); $monitor(a %d at %t, a, $time); fork #1 a 1; #2 a 2; join_any $display(Exit fork at %t, $time); #1 a 0; end 输出 Enter fork at 2 a x at 2 Exit fork at 3 a 1 at 3 a 0 at 4上例中当a1在3ns时执行完毕后控制即可跳出并行块但在随后1ns仿真器就要面临一个选择是先执行a2还是a0begin-end块的性质是否能保证a2一定在a0之前执行答案是否定的虽然结果表明a2在a0之前执行最终结果为0但这不是一定的比如下面的反例。//例6 reg [1:0]a; initial begin #2 $display(Enter fork at %t, $time); $monitor(a %d at %t, a, $time); fork a 1; #1 a 2; join_any $display(Exit fork at %t, $time); #1 a 0; end 输出 Enter fork at 2 Exit fork at 2 a 1 at 2 a 2 at 3由输出可以清晰地看出a2时在a0后发生最终结果为2。即begin-end块只能保证在同一仿真时间fork块中的第一条执行的语句是在fork块后语句之前的而无法保证其他同一仿真时间的语句的执行顺序。由于篇幅较长本文分上、下两节更新SystemVerilog基础并行块fork-join、join_any、join_none下https://blog.csdn.net/weixin_45791458/article/details/135036768?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22135036768%22%2C%22source%22%3A%22weixin_45791458%22%7D