Verilog HDL语法-行为级建模
过程语句
Verilog HDL中过程块由过程语句组成。过程语句有两种,分别是initial过程语句和always过程语句。
initial过程语句
initila过程语句的语法格式:
initial
begin
语句1;
语句2;
...
语句n;
end
说明:
1.initial过程块从仿真的0时刻开始执行。
2.在仿真过程中只执行一次。
3.如果一个模块中有多个initial过程块时,每个initial过程块都从仿真0时刻开始并行执行。
4.initial过程块中的语句既可以串行执行也可以并行执行(后面会介绍并行语句块)。
5.initial过程块不可被综合。
always过程语句
always过程语句后面会跟着一个敏感事件列表。只有敏感事件列表中的敏感事件被触发才会执行always过程块中的语句。并且always在整个仿真过程中都有可能被触发,其语法格式如下:
always @(<敏感事件列表>)
语句块
说明:
1.敏感事件列表就是触发条件,只有在条件满足时才会执行always语句块中的语句。
2.敏感信号可以分为边沿敏感型和电平敏感型。如果是边沿敏感型需要在信号前加上posedge或negedge表示在上升沿或下降沿时触发always块。
3.当敏感事件列表中有多个信号时可以使用or或","来连接多个敏感信号。
过程语句使用中的注意事项
1.在initial或always过程语句块中被赋值的信号必须被定义为reg类型。
2.采用过程语句块对组合逻辑电路进行描述时,需要把全部的输入信号都列入敏感事件列表。
3.采用过程语句块对时序电路进行描述时,需要把事件信号和部分输入信号列入敏感事件列表。
语句块
在Verilog HDL中当语句数超过一条是,需要使用语句块表示符将多条语句打包到一起。当只有一条语句时就不再需要语句块标识符了。
语句块包括串行语句块(begin-end)和并行语句块(fork-join)。
串行语句块
串行语句块的关键字是begin-end。串行语句块中的语句会被顺序执行。语法格式如下:
begin:块名
语句1;
语句2;
...
语句n;
end
说明:
1.块名是一个语句块的标识符,一般可以没有。但是当块内有变量时必须有块名(可以通过块名找到块内的变量)。
2.串行语句块从执行第一条语句开始执行,到最后一条语句执行完毕才结束。
3.串行语句块可以被综合。
并行语句块
并行语句块的关键字是fork-join。并行语句块中的语句会被并行执行。语法格式如下:
fork:块名
语句1;
语句2;
...
语句n;
end
说明:
1.并行语句块不可用于可综合的电路程序,只能用于仿真测试电路。
过程赋值语句
过程块中的赋值语句被称为过程赋值语句。由于过程赋值语句是在initial和always过程块内的赋值,所以过程赋值语句只能对寄存器类型的变量进行赋值。过程赋值语句分为阻塞赋值和非阻塞赋值两种。
阻塞赋值语句
阻塞赋值的符号为"="。
当一个串行语句块中有多条阻塞赋值语句时,只有前面的阻塞赋值语句完成后,才会执行后面的阻塞赋值语句。正因为这样,这种赋值方式才被称为阻塞赋值。
阻塞赋值语句的执行过程是:先计算等号右边的表达式的结果,然后立即将计算结果赋值给等号组边的变量,与仿真时间无关。
非阻塞赋值语句
非阻塞赋值的符号为"<="。
在一个串行语句块中有多条非阻塞赋值语句时,多条非阻塞赋值语句会同时被执行,执行的顺序没有先后之分。
非阻塞赋值语句的执行过程是:先计算等号右端的表达式,然后等待延迟时间的结束再将计算结果赋值给等号左边的变量。
阻塞赋值语句和非阻塞赋值语句综合后电路的差别
两种赋值语句都是可综合的。但是这两种语句对于电路的描述差别很大。下面用两个例子加以说明:
例1:
module block1(din,clk,out1,out2);
inout din, clk;
output out1,out2;
reg out1, out2;
always @(posedge clk)
begin
out1 = din;
out2 = out1;
end
endmodule
上面的例子中,当时钟的上升沿到来时,首先把输入的din信号赋值给输出信号out1。这相当于一个寄存器。在这个过程完成后会立即把更新的out1的值赋值给out2。这相当把out2直接连接在了out1上。所以综合出的电路如下图:
例2:
module block2(din,clk,out1,out2);
input din, clk;
output out1, out2;
reg out1, out2;
always @(posedge clk)
begin
out1 <= din;
out2 <= out1;
end
endmodule
与第一个例子不同的是,在例2中使用了非阻塞赋值。由于非阻塞赋值是同时执行的。所以在时钟的上升沿到来时会同时把din赋值给out1,未更新的的out1信号赋值给out2。所以这就相当于两个寄存器。综合出的电路如下图:
也可以使用阻塞赋值实现上面的电路,代码如下:
module block3(din,clk,out1,out2);
input din, clk;
output out1, out2;
reg out1, out2;
always @(posedge clk)
begin
out2 = out1;
out1 = din;
end
endmodule
连续赋值语句
在always和initial过程语句中也可以对连线型和寄存器型变量进行连续赋值。过程块中的连续赋值有两种方式,分别是赋值、重新赋值语句和强制、释放语句。
赋值语句和重新赋值语句
赋值和重新赋值的关键字是assign和deassign。语法格式为:
assign <寄存器类型变量> = <赋值表达式>;
deassign <寄存器类型变量>;
说明:
1.过程块中的连续赋值语句只能只能用于对寄存器类型的变量赋值,不可用于对线性变量赋值。
2.assign给寄存器型变量赋值后,这个值将一直保持在这个寄存器上。
3.deassign用于释放assign对寄存器变量的连续赋值。作用后变量的值保持不变,只是可以被重新赋值。
4.连续赋值不能对寄存器型变量进行位操作,例如:assign[1] = 1;会出现语法错误。
强制语句和释放语句
强制语句和强制释放语句的关键字是force和release。与assign,deassign不同的是force,release可以对连线型和寄存器型的变量进行赋值操作。语法格式如下:
force <寄存器或连线型变量> = <赋值表达式>;
release <寄存器或连线型变量>;
说明:
1.force语句的优先级高于assign语句。
条件分支语句
Verilog HDL的条件分支语句有两种:if条件分支语句和case条件分支语句。
if条件分支语句
//形式1
if(条件表达式) 语句块;
//形式2
if(条件表达式)
语句块1;
else
语句块2;
//形式2
if(条件表达式1)
语句块1;
else if (条件表达式2)
语句块2;
...
else if (条件表达式i)
语句块i;
else
语句块n;
case条件分支语句
if条件分支语句只有两个分支。在需要有多个分支的情况时可以使用case语句。case语句是一种可以实现多路分支选择控制的语句。case语句的语法格式是:
case(控制表达式)
值1: 语句块1;
值2: 语句块2;
...
值n: 语句块n;
default: 语句块n+1;
endcase
当case语句中控制表达式的值与值1相等时,执行语句块1。然后依次类推。如果都不相等时则执行default语句后的语句块。
case语句对控制表达式和其后的值进行比较时是一种全等比较。必须保证两者对应位全等。其比较真值表如下:
case | 0 | 1 | x | z |
---|---|---|---|---|
0 | 1 | 0 | 0 | 0 |
1 | 0 | 1 | 0 | 0 |
x | 0 | 0 | 1 | 0 |
z | 0 | 0 | 0 | 1 |
说明:
1.值1到值n必须各不相同。
2.一旦执行某个分支后,case语句的执行便结束。
3.case语句的所有表达式的值得位宽必须相等,只有这样控制表达式和分支表达式才能进行对应位的比较。
casez和casex条件分支语句
除了case条件分支语句外还有casez和casex条件分支语句。casez和casex语句时case语句的两种特殊形式,三者语法格式完全相同。差别在于,在casez语句中,如果比较的双方(控制表达式与值项)有一边的某一位的值是z,那么这一位的比较久不予考虑,即认为这一位的比较结果永远是真。而在casex语句中,则把这种处理方式进一步扩展到对x的处理。真值表如下:
casez | 0 | 1 | x | z |
---|---|---|---|---|
0 | 1 | 0 | 0 | 1 |
1 | 0 | 1 | 0 | 1 |
x | 0 | 0 | 1 | 1 |
z | 1 | 1 | 1 | 1 |
casex | 0 | 1 | x | z |
---|---|---|---|---|
0 | 1 | 0 | 1 | 1 |
1 | 0 | 1 | 1 | 1 |
x | 1 | 1 | 1 | 1 |
z | 1 | 1 | 1 | 1 |
循环语句
Verilog HDL中规定了4种循环语句,分别是forever,repeat,while和for循环语句。
forever循环语句
forever关键词引导的语句表示永久循环,直到遇到$finish。如果需要从forever中退出,则可以使用disable语句。forever语句的语法格式是:
forever 语句或语句块;
forever语句一般用在initial过程语句块中。如果在forever语句中没有加入时延控制,forever语句将在0时延后无限循环下去(在仿真0时刻一直循环,不能推进仿真时间?)。
repeat循环语句
repeat引导的循环语句只执行固定次数的循环,其语法格式是:
repeat(循环次数表达式)
语句或语句块(循环体);
循环次数表达式用于指定循环次数,它必须是一个常数、一个变量或者一个信号。
while循环语句
while循环是一种条件循环。while语句根据条件表达式的真假来确定循环体的执行。当指定的条件表达式为真时才会重复执行循环体。语法格式是:
while(条件表达式)
语句或语句块;
while语句块会先判断条件表达式是否为真,如果是,则执行后面的语句。语句执行完后会继续判断条件表达式是否为真,只要是真,再执行语句。直到某次条件表达式为非真,则退出循环。
for循环语句
for引导的循环也是一种条件循环,只有在指定的条件表达式成立时才进行循环。语法格式是:
for(循环变量赋初值; 循环结束条件; 循环变量增值) 语句块;
for循环的语句的执行过程是:先给循环变量赋初值,然后判断循环结束条件,若其值为真,则执行for循环中的语句块,然后进行循环变量增值。这一过程一直进行,直到循环结束条件满足时,for循环语句结束。
注意:for循环语句可以用于可综合电路的设计。
过程语句的可综合性
类别 | 语句 | 可综合性 |
过程语句 | initial | |
always | √ | |
语句块 | 串行语句块begin-end | √ |
并行语句块fork-join | ||
赋值语句 | 连续赋值语句assign | √ |
过程赋值语句=, <= | √ | |
条件语句 | if-else | √ |
case, casez, casex | √ | |
循环语句 | forever | |
repeat | ||
while | ||
for | √ | |
编译导向语句 | `define | √ |
`include | √ | |
`ifdef, `else, `endif | √ |