在自己准备写一些简单的verilog教程之前,参考了许多资料----Asic-World网站的这套verilog教程即是其一。这套教程写得极好,奈何没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。
这是网站原文:Verilog Tutorial
这是系列导航:Verilog教程系列文章导航
和C语言等程序语言类似,Verilog语法中的 if - else 语句可以根据条件的真假来选择执行不同分支的语句。如果每个分支需要执行的语句不止一条,则需要将这些语句都包含在 begin-end 语句之中。
不带有分支的单独的if语句的一般语法:
if (condition) //如果条件为真
statements; //则执行这条语句
以下代码:当使能信号enable为真即执行语句latch <= din;
module simple_if();
reg latch;
wire enable,din;
always @ (enable or din)
if (enable) begin
latch <= din;
end
endmodule
带有分支的if-else语句的一般语法:
if (condition) //如果条件为真
statements; //则执行这条语句
else //否则,即条件为假
statements; //则执行这条语句
以下代码:当复位信号reset为真即执行语句dff <= 0;否则执行语句dff <= din;
module if_else();
reg dff;
wire clk,din,reset;
always @ (posedge clk)
if (reset) begin
dff <= 0;
end else begin
dff <= din;
end
endmodule
多级的if-else if-else语句的一般语法:
if (condition1) //如果条件1为真
statements; //则执行这条语句
else if (condition2) //如果条件1为假但是条件2为真
statements; //则执行这条语句
................
................
else //如果以上所有例举的条件均为假
statements; //则执行这条语句
以下代码:当复位信号reset为真即执行语句counter <= 4'b0000;当复位信号reset为假且使能信号为真与up_en信号为真即执行语句counter <= counter + 1; 当复位信号reset为假且使能信号为真且up_en信号为假与up_down信号为真即执行语句counter <= counter - 1; 当以上所有条件均不满足,则执行语句 counter <= counter;
module nested_if();
reg [3:0] counter;
reg clk,reset,enable, up_en, down_en;
always @ (posedge clk)
if (reset == 1'b0) begin
counter <= 4'b0000;
end else if (enable == 1'b1 && up_en == 1'b1) begin
counter <= counter + 1'b1;
end else if (enable == 1'b1 && down_en == 1'b1) begin
counter <= counter - 1'b1;
end else begin
counter <= counter;
end
endmodule
在上面的例子中条件2(enable == 1'b1 && up_en == 1'b1)比条件3(enable == 1'b1 && down_en == 1'b1)的优先级要高,也就是说当up_en == 1'b1与down_en == 1'b1同时有效时(其他条件相同),此时执行的是条件2对应的执行语句。
这种优先级的if-else语句消耗的资源要比没有优先级的资源多(判断优先级需要消耗资源),有时我们并不需要对条件做优先级的判断,比如2个输入在逻辑上一定是互斥的情况,这时就可以使用并行的if-else语句来节省资源。
module parallel_if();
reg [3:0] counter;
wire clk,reset,enable, up_en, down_en;
always @ (posedge clk)
if (reset == 1'b0) begin
counter <= 4'b0000;
end else begin
if (enable == 1'b1 && up_en == 1'b1) begin
counter <= counter + 1'b1;
end
if (enable == 1'b1 && down_en == 1'b1) begin
counter <= counter - 1'b1;
end
end
endmodule
同样的,和C语言等程序语言类似,Verilog语法除了 if - else 语句外,也有case语句。case语句会列出多个条件(后边跟执行语句),从上到下根据条件的真假判断来执行对应分支的语句。如果每个分支需要执行的语句不止一条,则需要将这些语句都包含在 begin-end 语句之中。
这是case语句的一般语法:
case () //条件
< case1 > : < statement > //条件在这里满足执行对应语句
< case2 > : < statement > //条件在这里满足执行对应语句
..... //--
default : < statement > //所有情况都不满足则执行这条语句endcase
这是一个例子:
module mux (a,b,c,d,sel,y);
input a, b, c, d;
input [1:0] sel;
output y;
reg y;
always @ (a or b or c or d or sel)
case (sel) //sel的值即为条件
0 : y = a; //当sel = 0时执行y = a;
1 : y = b; //当sel = 1时执行y = b;
2 : y = c; //当sel = 2时执行y = c;
3 : y = d; //当sel = 3时执行y = d;
default : $display("Error in SEL"); //当sel不为上面列出的任何一个值时执行这条语句
endcase
endmodule
default关键字的作用是保证那些没有被例举出来的情况也有对应的执行语句。如果不使用 default 关键字,就需要将所有情况都一一列出,非常麻烦,就像这样:
module mux_without_default (a,b,c,d,sel,y);
input a, b, c, d;
input [1:0] sel;
output y;
reg y;
always @ (a or b or c or d or sel)
case (sel)
0 : y = a;
1 : y = b;
2 : y = c;
3 : y = d;
2'bxx,2'bx0,2'bx1,2'b0x,2'b1x,
2'bzz,2'bz0,2'bz1,2'b0z,2'b1z : $display("Error in SEL");
endcase
endmodule
由于在verilog语法中,合法的值有4种:0,1,x,z。所有除了case语句外,还有casex与casez语句,他们的用法是这样的:
下面的代码将case、casex与casez语句的用法做了一个比较:
module case_compare;
reg sel;
initial begin
#1 $display ("\n Driving 0");
sel = 0;
#1 $display ("\n Driving 1");
sel = 1;
#1 $display ("\n Driving x");
sel = 1'bx;
#1 $display ("\n Driving z");
sel = 1'bz;
#1 $finish;
end
always @ (sel)
case (sel)
1'b0 : $display("Normal : Logic 0 on sel");
1'b1 : $display("Normal : Logic 1 on sel");
1'bx : $display("Normal : Logic x on sel");
1'bz : $display("Normal : Logic z on sel");
endcase
always @ (sel)
casex (sel)
1'b0 : $display("CASEX : Logic 0 on sel");
1'b1 : $display("CASEX : Logic 1 on sel");
1'bx : $display("CASEX : Logic x on sel");
1'bz : $display("CASEX : Logic z on sel");
endcase
always @ (sel)
casez (sel)
1'b0 : $display("CASEZ : Logic 0 on sel");
1'b1 : $display("CASEZ : Logic 1 on sel");
1'bx : $display("CASEZ : Logic x on sel");
1'bz : $display("CASEZ : Logic z on sel");
endcase
endmodule
其仿真结果是这样的:
Driving 0
Normal : Logic 0 on sel
CASEX : Logic 0 on sel
CASEZ : Logic 0 on selDriving 1
Normal : Logic 1 on sel
CASEX : Logic 1 on sel
CASEZ : Logic 1 on selDriving x
Normal : Logic x on sel
CASEX : Logic 0 on sel
CASEZ : Logic x on selDriving z
Normal : Logic z on sel
CASEX : Logic 0 on sel
CASEZ : Logic 0 on sel
因为x在casex中视为不在乎,所以直接选择第一条语句有效,即打印 Logic 0 on sel ;同样的,因为z在casez和casex中均视为不在乎,所以都选择第一条语句有效,即打印 Logic 0 on sel。