块语句的作用是将多条语句合并成一组,使它们像一条语句那样。可以使用关键字begin和end将多条语句合并在一起。由于这些语句需要一条接一条的顺序执行,常称为顺序块。
Verilog语言中的块语句为顺序块和并行块。3种有特点的块语句为命名块,命名块的禁用和嵌套的块。
目录
一.块语句的类型:
块语句包括两种类型,分别是顺序块和并行块。
1.顺序块(也称过程块)
关键字begin—end用于将多条语句组成顺序块。其特点有以下两点:
(1)顺序块中的语句是一条接着一条按顺序执行的,执行完了前面的语句之后,才可以执行后面的语句,带有内嵌延迟控制的非阻塞赋值语句除外。
(2)如果语句包括延迟或事件控制,那么延迟总是相对于前面那条语句执行完成的仿真时间的。
下面的例子给出了两个顺序块语句,顺序块中的语句按顺序执行。
【例1】
//说明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
说明1,在仿真0时刻,x,y,z,w的最终值分别是0、1、1、2。
执行这四个赋值语句有顺序,不需要执行时间。
x,y,为寄存器类型,reg x,y; {}是位拼接运算符,z = {x,y},z的值为x和y拼接后的结果,二进制表示为01,十进制为1。同理,w的值为y和x拼接后的结果,二进制表示为10。
因此,在仿真0时刻,x、y、z、w最终值分别为0、1、1、2。
说明2,这四个变量的最终值也是0、1、1、2。但块语句完成时刻为35,因此除第一句外,以后每执行一条语句都需要等待。
2.并行块:
并行块由关键字fork—join声明,它的仿真特点是很有趣的。具有以下特性:
(1)并行块内的语句并发执行。
(2)语句执行的顺序是由各自语句内的延迟或事件控制决定的。
(3) 语句中的延迟或事件控制是相对于块语句开始执行的时刻而言的。
注:顺序块和并行块之间的根本区别在于:当控制转移到块语句的时刻,并行块中所有的语句同时开始执行,语句之间的先后顺序是无关重要的。例1中说明2,带延迟的顺序块,可以将其转换成一个并行块。转换后为例2。除了所有语句在仿真0时刻开始执行以外,仿真结果是完全相同的,此并行块执行结果的时间第20个仿真时间单位,而不再是35个。
【例2】
//带延迟的并行块
reg x,y;
reg[1:0] z,w;
initial
fork
x = 1'b0; //在仿真时刻0完成
# 5 y = 1'b1; //在仿真时刻5完成
# 10 z = {x,y}; //在仿真时刻10完成
# 20 w = {y,x}; //在仿真时刻20完成
join
并行块为我们提供了执行语句的机制。不过在使用并行块时需要注意,如果两条语句在同一时刻对同一变量产生影响,那么将会引起隐含的竞争,这种情况是需要避免的。例3给出了例1中说明1的并行块描述。在这段代码中故意引入了竞争。所有的语句在仿真0时刻开始执行,但是实际的执行顺序是未知的。在例3中如果x = 1'b0 和 y = 1'b1这两条语句首先执行,那么变量z和w的值为1和2;如果这两条最后执行,那么z和w的值都是2‘bxx。因此执行这个块语句后z和w的值不确定,依赖于仿真器的具体实现方法。从仿真的角度来讲,并行块中的所有语句是一块执行的,但是实际上运行仿真程序的CPU在任一时刻只能执行一条语句,而且不同的仿真器按照不同的顺序执行。因此无法正确的处理竞争是目前所使用的仿真器的一个缺陷,这一缺陷并不是并行块所引起的。
【例3】
//故意引入竞争条件的并行块
reg x,y;
reg[1:0] z,w;
initial
fork
x = 1'b0;
y = 1'b1;
z = {x,y};
w = {y,x};
join
可以将并行块的关键字fork看成是将一个执行流分成多个独立的执行流;而关键字join则是将多个独立的执行流合并成一个执行流。每个独立的执行流之间是并发执行的。
二.块语句的特点:
块语句有三个特点,分别是:嵌套块、命名块和命名块的禁用。
1.嵌套块
块可以嵌套使用,顺序块和并行块能够混合在一起使用。
【例4】嵌套块
//嵌套块
initial
begin
x = 1'0;
fork
# 5 y = 1'b1;
#10 z = {x,y};
join
# 20 w = {y,x};
end
endmoudle
2.命名块:
块可以具有自己的名字,这就称为命名块,命名块的特点是:
(1)命名块中可以声明局部变量。
(2)命名块是设计层次的一部分,命名块中声明的变量可以通过层次名应用进行访问。
(3)命名块可以被禁用,例如停止其执行。
3.命名块的禁用
Verilog通过关键字disable提供了一种中止命名块执行的方法。disable可以用来从循环中退出、处理错误条件以及根据控制信号来控制某些代码段是否被执行。对块语句的禁用导致紧接在块后面的那条语句被执行。
这一点非常类似于使用break退出循环。两者的区别在于break只能推出当前所在的循环,而使用disable则可以禁用设计中任意一个命名块。
【例5】在一个标志寄存器中查找第一个不为零的位,while循环可以使用disable来进行改写,使得在找到不为零的位后马上退出while循环。
//在(矢量)标志寄存器的各个位中从低有效位开始找寻第一个值为1的位
//从矢量标志寄存器的低有效位开始查找第一个值为1的位
reg [15:0] flag;
initial i; //用于计数的整数
initial
begin
flag = 16'b 0010_0000_0000_0000;
i = 0;
begin : block1 //while循环声明中的主模块是命名块block1
while(i<16)
begin
if(flag[i])
begin
$ display("Encountered a TRUE bit at element number %d",i);
disable block1; //在标志寄存器中找到值为真(1)的位,禁用block1
end
i = i + 1;
end
end
end