verilog初识-条件语句、循环语句、块语句
1.条件语句
1.1条件语句(if_else语句)
if语句用来判断给定的条件是否满足,根据判断的结果决定要执行的操作。verilog HDL提供了3种形式的if语句。
- (1) if(表达式) 语句。
如:
if(a>b) out1= in1; - (2) if(表达式) 语句1;
else 语句2;
如:if(a>b) out1=in1;
else out1=in2; - (3) if(表达式1) 语句1;
else if(表达式2) 语句2;
else if(表达式3) 语句3;
…
else 语句n;
如:
if(score>90) level=1;
else if(score>80) level=2;
else if(score>70) level=3;
else if(score>60) level=4;
else level=5;
- tips:
- (1)条件语句必须在过程块语句中使用。所谓过程块语句指的是由initial和always语句引导的执行语句集合。除这两种块语句引导的begin end块中可以编写条件语句外,模块中其他地方都不能编写。
如:
always@(some_event)
begin
if(a>b) out=in1;
ese if(a==b) out=in2;
else out=in3;
end - (2)if后面的表达式一般为逻辑表达式或关系表达式,系统对表达式的值进行处理,若表达式结果为0,x,z,按“假”处理,若为1,按“真”处理。
- (3)在if和else后面可以包含一个内嵌的操作语句,也可以有多个操作语句,此时用begin和end将几个语句包含起来成为一个复合块语句。
如:
- (1)条件语句必须在过程块语句中使用。所谓过程块语句指的是由initial和always语句引导的执行语句集合。除这两种块语句引导的begin end块中可以编写条件语句外,模块中其他地方都不能编写。
if(a>b)
begin
out1=in1;
out2=in2;
end
else
begin
out1=in2;
out2=in1;
end
- (4)允许一定形式的表达式简写方式。如:
if(expression)等同于if(expression==1)
if(!expression)等同于if(expression!=1) - (5)if语句的嵌套:在if语句中又包含一个或多个if语句称为if语句的嵌套。一般形式如下:
if(expression1)
if(expression2) 语句1;//(内嵌if)
else 语句2;
else
if(expression3) 语句3;//(内嵌if)
else
语句4;
注:else总是与它上面最近的if配对。如果if与else的数目不一样,可以用begin_end块语句来确定配对关系。
其结构如下:
if()
begin
if()语句1;//(内嵌if)
end
else
语句2;
如:
if(index>0)
begin
for(scani=0;scani<index;scani=scani+1)
if(memory[scani]>0)
begin
$display(“…”);
memory[scani]=0;
end
end
else
$display(“error-indexiszero”);
tips:
if语句通常只有两个分支可供选择,多于两个分支需要使用if嵌套。1.2.条件语句(case语句)
case语句是一种多分支语句,通常包含两个或多个分支语句。
其结构形式为:
- (1)case(表达式)
分支表达式: 语句1;
…
默认项(default项): 语句n;
endcase - (2)casez(表达式)
分支表达式: 语句1;
…
默认项(default项): 语句n;
endcase - (3)casex(表达式)
分支表达式: 语句1;
…
默认项(default项): 语句n;
endcase
其中语句1,语句2,…,语句n可以是1条语句或多条语句,当为多条语句时,需要使用begin_end来将多条语句组合为一个语句块。
特点:
(1)case()里面的表达式也称控制表达式,常亮表达式,当控制表达式的值与分支表达式的值相等时,执行分支表达式后面对应的语句,如果所有分支表达式的值都没有与控制表达式的值相匹配,则执行dafault后面的语句。
(2)每一个case分支表达式的值必须互不相同。
(3)当case执行完分支语句,即终止其他case语句的执行。
(4)case语句的所有表达式值的位宽必须相等,注意避免使用’bx,'bz来替代n’bx,n’bz,因为信号x和z的默认宽度为机器的字节宽度,通常是32位,而n是case控制表达式的位宽,二者通常情况下是不相等的。
如:
case(sig)
1’bz: $display(“signal is floating”);
1’bx: $display(“signal is unknown”);
default: $display(“signal is %b”,sig);
endcase
(5)casez和casex可以用来处理比较过程中不必考虑的情况,其中casez语句用来处理不考虑高阻值z的比较过程,casex语句则将高阻值z和不定值x都视为不必关心的情况。所谓的不必关心的情况,即在表达式进行比较时,不讲该位的状态考虑在内。
如(1):
reg[7:0] sig;
casez(sig)
8’b1???: instruction1(sig);
8’b0110???: instruction2(sig);
8’b???11000: instruction3(sig);
default:instruction4;
endcase
(2):
reg[7:0] r,mask;
mask = 8’bx00x00x1;
casex(r^mask)
8’b001011xx: stats1;
8’b1100xx00: stats2;
8’b0110xx11: stats3;
default:stats4;
endcase - tips:
- (1)条件语句编写时,注意在if后面要有对应的case语句,在case_endcase内部需要有default语句,这样可以避免出现不必要的锁存器。
如:
always @(al or d)
begin
if(al) q=d;
end
此代码缺少else语句,因此在执行时会生成锁存器。
正确的(避免不必要锁存器出现)代码为:
always @(al or d)
begin
if(al) q=d;
else q=0;
end
同理,如果在case_endcase语句内部没有default语句,也会生成锁存器。 - (2)case语句的行为类似多路选择器。
如:使用case语句实现四选一多路选择器:
- (1)条件语句编写时,注意在if后面要有对应的case语句,在case_endcase内部需要有default语句,这样可以避免出现不必要的锁存器。
module mux4_to_1(out,i0,i1,i2,i3,s1,s0);
//输入输出端口声明
output out;
input i0,i1,i2,i3;
input s1,s0;
//输出变量类型声明
reg out;
//任何输入信号变化,都会引起输出信号的状态更新
always@(s1 or s0 or i0 or i1 or i2 or i3)
begin
case({s1,s0})
2'b00: out = i0;
2'b01: out = i1;
2'b10: out = i2;
2'b11: out = i3;
default: out = 1'bx;
endcase
end
endmodule
2.循环语句
在verilog HDL中存在着4种类型的循环语句,用来控制执行语句的执行次数。
- forever语句:连续的执行语句。
- repeat语句:连续执行一条语句n次。
- while语句:执行一条语句直至某个条件不满足。如果一开始条件就不满足,则语句一次也不执行。
- for语句:根据设定的条件执行指定的次数
2.1 forever语句
forever语句,常用于产生周期性的波形,用作仿真测试信号。与always的不同之处在于它不能独立写在程序中,而是必须写在initial块中。
格式如下:
forever 语句;
或
forever
begin
多条语句;
end
2.2 repeat语句
格式如下:
repeat(表达式) 语句
或
repeat(表达式)
begin
多条语句;
end
在repeat语句中,其表达式通常为常量表达式。
如:使用repeat循环语句及加法和移位操作来实现一个乘法器:
paremeter size=8;longsize=16;
reg[size-1] opa,opb;
reg[longsize-1] result;
begin:mult
reg[longsize:1] shift_opa,shift_opb;
shift_opa=opa;
shift_opb=opb;
result=0;
repeat(size)
begin
if(shift_opb[1])
result=result+shift_opa;
shift_opa=shift_opa<<1;
shift_opb=shift_opb>>1;
end
end
2.3 while语句
格式如下:
while(表达式) 语句;
或
while(表达式)
begin
多条语句;
end
如:统计1个八位二进制数中1的个数:
begin: count1s
reg[7:0] tempreg;
count = 0 ;
tempreg = rega;
while(tempreg)
begin
if(tempreg[0]) count = count + 1;
tempreg = tempre >> 1;
end
end
2.4 for语句
格式如下:
for(表达式1;表达式2;表达式3)
语句;
表达式1对变量初始化,表达式2对变量满足的条件进行判断,如果满足,执行表达式3,否则结束循环。
最常见的形式如下:
for(循环变量赋初值;循环结束条件;循环变量增值)
如(1)初始化memeory:
begin: init_mem
reg[7:0] tempi;
for(tempi=0;tempi<memsize;tempi=tempi+1)
memory[tempi]=0;
end
(2)实现乘法器(与repeat语句中的例子执行结果相同)
parameter size=8,longsize=16;
reg[size:1] opa,opb;
reg[longsize:1] result;
begin:mult
integer cnt;
result = 0;
for(cnt=1;cnt<=size;cnt=cnt+1)
if(opb[cnt])
result=result+(opa<<(cnt-1));
end
3.块语句
3.1 块语句的类型
块语句包含两种类型:
- 顺序块,如always,begin_end,语句块内部顺序执行
- 并行块,如fork_join,语句块内部并发执行
3.2 块语句的特点
块语句具有3个特点:
- 嵌套块
- 命名块
- 命名块的禁用
3.2.1 嵌套块
嵌套块,在块语句内部调用其他块语句。
如:
initial
begin
x=1'b0;
fork//内部嵌套
#5 y=1'b1;//在第5个单位时间开始执行
#10 z={x,y};//将x与y拼接,然后赋值给z,在第10个单位时间开始执行
join
#20 w={y,x};//在第20个单位时间开始执行
end
endmodule
3.2.1 命名块
命名块,指的是给块赋予名字。其特点如下:
- 命名块中可以声明局部变量;
- 命名块是设计层次的一部分,命名块中声明的变量可以通过层次名引用进行访问;
- 命名块可以被禁用,例如使用disable停止其执行。
如:
module top;//指定模块名为top
initial
begin:block1//为顺序块命名为block1
integer i;//整形变量i是block1命名块的静态局部变量,在其他模块或者命名块中可以使用层次名top.block1.i对其进行访问
...
end
intial
fork:block2//为顺序块命名为block2
reg i;//寄存器变量i是block2命名块的静态局部变量,在其他模块或者命名块中可以使用层次名top.block2.i对其进行访问
...
join
endmodule
3.2.1 命名块的禁用
verilog通过关键字disable提供了一种中止命令块执行的方法。disable可以用来从循环中退出、处理错误条件以及根据控制信号来控制某些代码段是否被执行。对块语句的禁用导致紧跟在块后面的那条语句被执行。
使用上与C语言的break类似,但是break只能退出当前所在的循环,而disable可以禁用任意一个命名块。
如:
reg[15:0] flag;
integer i;
initial
begin
flag = 16'b0010_1110_0100_1000;
i = 0;
begin:block1
while(i<16)
begin
if(flag[i])
begin
$display("encounted a true bit at element number %d",i);
disable(block1);//当在寄存器中找到值为1的第一个位置,禁用block1
end
else i=i+1;
end
end
end