顺序块:
关键字begin - end用于将多条语句组成顺序块。顺序块具有以下特点:
(1)顺序块中的语句是一条接一条按顺序执行的,只有前面的语句执行完成之后才能执行后面的语句(除了带有内嵌延迟控制的非阻塞赋值语句)。
(2)如果语句包括延迟或事件控制,那么延迟总是相对于前面那条语句执行完成的仿真时间的。
在[例5. 9]中进一步给出了两个顺序块语句的例子。顺序块之中语句按顺序执行,[例5.9]的说明1中,在仿真0时刻x、y、z、w的最终值分别为0、1、1、2(十进制)。执行这4个赋值语句有顺序,但不需要执行时间。在说明2中,这4个变量的最终值也是0、1、1、2,但块语句完成时的仿真时刻为35,因为除第一句外,以后每执行一条语句都需要等待。
【例5.9】顺序块
//说明1
reg x,y;
reg [1:0] z,w;
initial
begin
x=1'b0;
y=1'b1;
z={x,y};
w={y,x};
end
//说明2:带延迟的顺序块
reg x,y;
reg [1:0] z,w;
initial
begin
x=1'b0; //在仿真时刻0完成
#5 y=1'b1; //在仿真时刻5完成
#10 z={x,y}; //在仿真时刻15完成
#20 w={y,x}; //在仿真时刻35完成
end
并行块
并行块由关键字fork-join声明,它的仿真特点是很有趣的。并行块具有以下特性:
(1)并行块内的语句并发执行;
(2)语句执行的顺序是由各自语句内延迟或事件控制决定的;
(3)语句中的延迟或事件控制是相对于块语句开始执行的时刻而言的。
注意:顺序块和并行块之间的根本区别在于:当控制转移到块语句的时刻,并行块中所有的语句同时开始执行,语句之间的先后顺序是无关紧要的。请考虑[例5.9]中带有延迟的顺序块语句,并且将其转换为一个并行块。转换后的Verilog 代码见[例5.10]。 除了所有语句在仿真0时刻开始执行以外,仿真结果是完全相同的。这个并行块执行结束的时间第20个仿真时间单位,而不再是35个。
【例5.10】并行块
//举例1:带延迟的并行块
reg x, y;
reg[1:0] z,w;
initial
fork
x = 1'b0; //在仿真时刻0完成
#5 y=l'bl; //在仿真时刻5完成
#10 z={x,y}; //在仿真时刻10完成
#20 w={y, x}; //在仿真时刻20完成
join
并行块为我们提供了并行执行语句的机制。不过在使用并行块时需要注意,如果两条语句在同一时刻对同-一个变量产生影响,那么将会引起隐含的竞争,这种情况是需要避免的。下面给出了[例5.9]中说明1的并行块描述。在这段代码中故意引人了竞争。所有的语句在仿真0时刻开始执行,但是实际的执行顺序是未知的。在这个例子中,如果x= 1’b0和y=1’b1两条语句首先执行,那么变量z和w的值为1和2;如果这两条最后执行,那么z和w的值都是2’bxx。因此执行这个块语句后z和w的值不确定,依赖于仿真器的具体实现方法。从仿真的角度来讲,并行块中的所有语句是一起执行的,但是实际上运行仿真程序的CPU在任一时刻只能执行一条语句,而且不同的仿真器按照不同的顺序执行。因此无法正确的处理竞争是目前所使用的仿真器的一个缺陷,这一缺陷并不是并行块所引起的。例如:
//故意引入竞争条件的并行块
reg x,y;
reg [1:0] z,w;
initial
fork
x = 1'b;
y = 1'b1;
z={x,y};
w={y,x};
join
可以将并行块的关键字fork看成是将-一个执行流分成多个独立的执行流;而关键字join,则是将多个独立的执行流合并为一个执行流。每个独立的执行流之间是并发执行的。