Verilog 中部分语句与C相似,但也有些与C不同,如块语句、生成语句、csesx和casez等,即使将新概念与硬件结构联系起来、
Verilog HDL语言提供了3种形式的if语句。
(1)
if (a > b)
out1 = int1;
(2)第二种形式
if (a > b)
out1 = int1;
else
out1 = int2;
(3)第三种形式
if (表达式1)
语句1;
else if (表达式2) 语句2;
else if (表达式3) 语句3;
.
.
.
else if (表达式m) 语句m;
else 语句n;
条件语句必须在过程块语句中使用。所谓过程块语句是指由initial 和 always 引导的执行语句集合。除了在这两个块语句中引导的 begin end 块中可以编写条件语句外,其他地方都不能编写。
if语句6点说明:
(1).三种形式的if语句中在if后面都有“表达式”,一般为逻辑表达式或关系表达式。系统对表达式的值进行判断,若为0,x,z,按“假”处理,若为1,按“真”处理,执行指定的语句。
(2) .第二、第三种形式的if语句中,在每个else前面有一分号,整个语句结束处有一分号。如上图程序所示。
但应注意,不要误认为if 语句1; else 语句 2 ;是两个语句。它们都属于同一个if语句。else子句不能作为语句单独使用,它必须是if语句的一部分,与if配对使用。
(3).在if和else后面可以包含一个内嵌的操作语句(如上例),也可以有多个操作语句,此时
用begin和end这两个关键词将几个语句包含起来成为一个复合块语句。如:
if(a>b)
begin
out1<=int1;
out2<=int2;
end
else
begin
out1<=int2;
out2<=int1;
end
注意在end后不需要再加分号。因为begin_end内是一个完整的复合语句,不需再附加分号。
(4).允许一定形式的表达式简写方式。如
if(expression) 等同与 if( expression == 1 )
if(!expression) 等同与 if( expression != 1 )
(5).if语句的嵌套
在if语句中又包含一个或多个if语句称为if语句的嵌套。
应当注意if与else的配对关系,else总是与它上面的最近的if配对。如果if与else的数目不
一样,为了实现程序设计者的企图,可以用begin_end块语句来确定配对关系。例如:
if( )
begin
if( ) 语句1 (内嵌if)
end
else
语句2
这时begin_end块语句限定了内嵌if语句的范围,因此else与第一个if配对。注意begin_end块语句在if_else语句中的使用。因为有时begin_end块语句的不慎使用会改变逻辑行为。
if语句只有两个分支可供选择,而实际问题中常常需要用到多分支选择,case语句是一种多分支选择语句,Verilog语言提供的case语句直接处理多分支选择。
它的一般形式如下:
1) case(表达式) endcase
2) casez(表达式) endcase
3) casex(表达式) endcase
case分支项的一般格式如下:
分支表达式: 语句
缺省项(default项): 语句
说明
(a)case括弧内的表达式称为控制表达式,case分支项中的表达式称为分支表达式。控制表达式通常表示为控制信号的某些位,分支表达式则用这些控制信号的具体状态值来表示,因此分支表达式又可以称为常量表达式。
(b)当控制表达式的值与分支表达式的值相等时,就执行分支表达式后面的语句。如果所有的分支表达式的值都没有与控制表达式的值相匹配的,就执行default后面的语句。
(c) default项可有可无,一个case语句里只准有一个default项。下面是一个简单的使用case语句的例子。该例子中对寄存器rega译码以确定result的值。
reg [15:0] rega;
reg [9:0] result;
case(rega)
16 'd0: result = 10 'b0111111111;
16 'd1: result = 10 'b1011111111;
16 'd2: result = 10 'b1101111111;
16 'd3: result = 10 'b1110111111;
16 'd4: result = 10 'b1111011111;
16 'd5: result = 10 'b1111101111;
16 'd6: result = 10 'b1111110111;
16 'd7: result = 10 'b1111111011;
16 'd8: result = 10 'b1111111101;
16 'd9: result = 10 'b1111111110;
default: result = 'bx;
endcase
d) 每一个case分项的分支表达式的值必须互不相同,否则就会出现矛盾现象(对表达式的同一个值,有多种执行方案)。
e) 执行完case分项后的语句,则跳出该case语句结构,终止case语句的执行。
f) 在用case语句表达式进行比较的过程中,只有当信号的对应位的值能明确进行比较时,比较才能成功。因此要注意详细说明case分项的分支表达式的值。
g) case语句的所有表达式的值的位宽必须相等,只有这样控制表达式和分支表达式才能进行对应位的比较。一个经常犯的错误是用’bx, 'bz 来替代 n’bx, n’bz,这样写是不对的,因为信号x, z的缺省宽度是机器的字节宽度,通常是32位(此处 n 是case控制表达式的位宽)。
Verilog HDL针对电路的特性提供了case语句的其它两种形式用来处理case语句比较过程中的不必考虑的情况( don’t care condition )。其中casez语句用来处理不考虑高阻值z的比较过程,casex语句则将高阻值z和不定值都视为不必关心的情况。所谓不必关心的情况,即在表达式进行比较时,不将该位的状态考虑在内。cazex即无论是输入或输出出现x或z时,输出就是1。
Verilog HDL设计中容易犯的一个通病是由于不正确使用语言,生成了并不想要的锁存器。下面我们
给出了一个在“always"块中不正确使用if语句,造成这种错误的例子。
在"always"块内,如果在给定的条件下变量没有赋值,这个变量将保持原值,也就是说会生成一个锁存器!
Verilog HDL程序另一种偶然生成锁存器是在使用case语句时缺少default项的情况下发生的。
case语句的功能是:在某个信号(本例中的sel)取不同的值时,给另一个信号(本例中的q)赋不同的值。注意看下图左边的例子,如果sel=0,q取a值,而sel=11,q取b的值。这个例子中不清楚的是:如果sel取00和11以外的值时q将被赋予什么值?在下面左边的这个例子中,程序是用Verilog HDL写的,即默认为q保持原值,这就会自动生成锁存器。
以上就是怎样来避免偶然生成锁存器的错误。如果用到if语句,最好写上else项。如果用case语句,最好写上defalut项。遵循上面两条原则,就可以避免发生这种错误,使设计者更加明确设计目标,同时也增强了Verilog程序的可读性。不写else或default变量就会保留原值,形成锁存器。
if else 语句的三种类型(没有else、有一条else、嵌套if_else_if 语句)可以生成条件语句。
case 语句采用关键词case、endcase和default来表示。case语句中的defalut语句是可选的,但是一条case语句中不允许出现多条defalut。而且case语句可以嵌套。
case语句可以生成多路分支语句
在Verilog HDL中存在着四种类型的循环语句,用来控制执行语句的执行次数。
forever 语句;
或
forever begin 多条语句 end
forever循环语句常用于产生周期性的波形,用来作为仿真测试信号。它与always语句不同处在于不能独立写在程序中,而必须写在initial块中。
repeat语句的格式如下:
repeat(表达式) 语句;
或
repeat(表达式) begin 多条语句 end
在repeat语句中,其表达式通常为常量表达式。repeat后边常量是几,就是就是循环执行几次。
下面的例子中使用repeat循环语句及加法和移位操作来实现一个乘法器。
parameter 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; //被乘数右移 判断是否为1
end
end
while语句的格式如下:
while(表达式) 语句
或:
while(表达式) begin 多条语句 end
表达式为假结束循环。
begin: count1s
reg[7:0] tempreg;
count=0;
tempreg = rega;
while(tempreg)
begin
if(tempreg[0]) count = count + 1;
tempreg = tempreg>>1;
end
end
while(寄存器)???、 是否合法?如何判断表达式是否为真?
for语句的一般形式为:
for(表达式1;表达式2;表达式3) 语句
它的执行过程如下:
(1) 先求解表达式1;
(2) 求解表达式2,若其值为真(非0),则执行for语句中指定的内嵌语句,然后执行下面的
第3步。若为假(0),则结束循环,转到第5步。
(3) 若表达式为真,在执行指定的语句后,求解表达式3。
(4) 转回上面的第2步骤继续执行。
(5) 执行for语句下面的语句。
for语句最简单的应用形式是很易理解的。
其形式如下:
for(循环变量赋初值;循环结束条件;循环变量增值)
执行语句
下面则是用for循环语句来实现前面用repeat语句实现的乘法器。
parameter size = 8, longsize = 16;
reg[size:1] opa, opb;
reg[longsize:1] result;
begin:mult
integer bindex;
result=0;
for( bindex=1; bindex<=size; bindex=bindex+1 )
if(opb[bindex])
result = result + (opa<<(bindex-1));
end
在for语句中,循环变量增值表达式可以不必是一般的常规加法或减法表达式。也可以是移位等运算算法。
例:for( tempreg=rega; tempreg; tempreg=tempreg>>1 )
在使用并行块时需注意,如果两条语句在同一时间对同一变量产生影响,那么将会引起隐含的竞争,这种情况需要避免。并行块中所有语句都是在仿真0时刻开始执行,但是实际的执行顺序是未知的。从仿真的角度来讲,并行块中的所有语句是一起执行的,但是实际上运行仿真程序的CPU在任一时刻只能执行一条语句,而且不同的仿真器按照不同的顺序执行。
块语句的特点
块语句具有三个特点:嵌套块、命名块、和命名块的禁用。
嵌套块
initial
begin
x=1'b0;
fork
#5 y = 1'b1;
#10 z = {x,y};
join
#20 w= {y,x};
end
endmodule
命名块
块可以有自己的名字,这称为命名块。命名块的特点是:
(1) 命名块中可以声明局部变量;
(2)命名块是设计层次的一部分,命名块中声明的变量可以通过层次名引用进行访问;
(3)命名块可以被禁用,例如停止其执行。
例如;
module top ;
initial
begin block1; //名字是block1的顺序命名块。
integer i; //可以用层次名 top.block1.i 被其他模块访问
命名块的禁用
Verilog采用关键字disable提供一种中止命名块执行的方法。disable可以用来从循环中退出,处理错误条件以及根据控制信号来控制某些代码段是否被执行。
例如:disable block1 ; //禁用块block1。
顶层模块调用其他模块时,正确填入I/O口的对应信号。
例如已有全加器模块FullAdder。在顶层模块中调用连接线分别为W4,W5,W3,W2和W1。
FullAdder FA(.Sum(W1),
.Cout(W2),
.Cin(W3),
.A(W4),
.B(W5));
定义端口线,正确填入I/O口对应的信号。
input [0:2];最高位MSB:IP[0]; 最低位IP[2];
wire[16:23]A 最高位MSB:A[16];最低位LSB:A[23];
与0按位异或是本身,与1按位异或为取反。
与0按位同或是取反,与1同位异或为本身。
一个<=,一个触发器。