Verilog有一套控制流块和机制来实现。它包括:
- if-else
- forever loop
- repeat loop
- while loop
- for loop
if条件语句
这个条件语句用来决定是否应该执行某些语句。这与C语言中的if-else-if语句非常相似。如果表达式的值为真,那么第一条语句将被执行。如果表达式的值为false,并且如果存在一个else部分,那么else部分将被执行。
如果需要在if或者else部分内放置多条语句,则需要用 begin和end括起来。
语法表达式:
// if statement without else part
if (expression)
[statement]
// Use "begin" and "end" blocks for more than 1 statements
if ([expression]) begin
Multiple statements
end
// if statment with an else part
if (expression)
[statement]
else
[statement]
// if else for multiple statements should be
// enclosed within "begin" and "end"
if (expression) begin
[multiple statements]
end
else begin
[multiple statements]
end
// if-else-if statement
if (expression)
[statement]
else if (expression)
[statement]
else
[statement]
// if-else-if style to check for more expressions if the previous one doesn't match
if ([expression 1])
Single statement
else if ([expression 2]) begin
Multiple Statements
end
else
Single statement
单独if
if没有else部分,意味着对于任何不满足if内部表达式的条件,其值保持不变。
保持不变的硬件对应位锁存器
,例:
module des ( input en,
input d,
output reg q);
always @ (*)
if (en)
q = d;
endmodule
RTL原理图:
带有else的if
如果rstn为高电平,输出q将在时钟的上升沿得到输入d的值,并描述了D触发器的行为。
module dff ( input clk,
input rstn,
input d,
output reg q);
always @ (posedge clk) begin
if (! rstn)
q <= 0;
else
q <= d;
end
endmodule
RTL原理图:
这个例子中是一个同步低电平复位,但从上图RTL原理图看出,仍然像是一个异步复位,因为复位信号的输出接到了触发器的rst端,这是什么情况呢?
在刚学习FPGA的时候我就遇到过这个一个问题,也就是综合的原理图(综合的情况应该和RTL原理图一致,只不过使用了某些器件的替换)和硬件语言描述的不一致问题。
原因:ISE软件中某些器件的D触发器自带了同步复位,所以看上去像异步复位!
在Verilog程序设计中,if_else语句和case语句都是选择语句,当满足某个条件是,就选择某一样状态,当然这两个语句也是有区别的。
if_else语句具有优先级
,是顺序执行的语句,所以我们在写if_else语句时需要对优先级进行考量,不然就会产生和我们设计不符的结果,并且还不容易发现错误。
case语句不具有优先级
,是一种并行执行的语句。在实际设计中,一般类别少时用if_else语句,类别多用case语句,if_else语句基本上可以处理所有的复杂判断条件,但是在实际电路中占用的资源较多,所以能用case语句尽量用case语句。
if-else-if
设计模块有一个4位输出q,当模式为1时递增,当模式为2时递减,使用if else结构。请注意,描述中没有说明如果模式为0或3时要做什么,这些都是2位变量的有效值。假设当模式为1和3时,电路什么都不做,但保持q的退出值,不建议在实际设计代码中留下这种含糊不清的地方,但在这里是为了强调这种可能性。
module des (
input [1:0] mode,
input clk,
input rstn,
output reg [3:0] q);
always @ (posedge clk) begin
if (! rstn)
q <= 0;
else begin
if (mode == 1)
q <= q + 1;
else if (mode == 2)
q <= q - 1;
end
end
endmodule
循环语句
foever
这将连续执行块内的语句,不可综合。
forever
[statement]
forever begin
[multiple statements]
end
这条语句常用于仿真中生成时钟信号,例如:
initial begin
clk = 0;
end
forever begin
#5 clk = ~clk;
end
repeat
这将执行固定次数的语句。如果表达式的值是X或Z,那么它将被视为零,根本不会被执行。不可综合。
repeat ([num_of_times]) begin
[statements]
end
repeat ([num_of_times]) @ ([some_event]) begin
[statements]
end
module my_design;
initial begin
repeat(4) begin
$display("This is a new iteration ...");
end
end
endmodule
仿真结果:
This is a new iteration ...
This is a new iteration ...
This is a new iteration ...
This is a new iteration ...
while
只要表达式为真,就会执行语句,一旦条件为假,就会退出。如果条件从一开始就是假的,则根本不会执行语句。不可综合。
while (expression) begin
[statements]
end
module my_design;
integer i = 5;
initial begin
while (i > 0) begin
$display ("Iteration#%0d", i);
i = i - 1;
end
end
endmodule
仿真结果:
Iteration#5
Iteration#4
Iteration#3
Iteration#2
Iteration#1
for
for循环是软件中使用最广泛的循环,但它主要用于复制Verilog中的硬件逻辑。for循环背后的思想是,只要给定的条件为真,就对循环内给定的一组语句进行迭代。这与while循环非常相似,但更多的是用在有迭代器的情况下,条件取决于这个迭代器的值。
for (<initial_condition>; <condition>; <step_assignment>) begin
// Statements
end
- 初始条件指定信号的初始值
- 用于评估给定条件是否为真的检查。
- 更新下一次迭代的控制变量
注:for循环使用得当,是可以综合的。
8为左移寄存器使用传统和for循环对比:
传统方法:
module lshift_reg (input clk, // Clock input
input rstn, // Active low reset input
input [7:0] load_val, // Load value
input load_en, // Load enable
output reg [7:0] op); // Output register value
always @ (posedge clk) begin
if (!rstn) begin
op <= 0;
end
else begin
if (load_en) begin
op <= load_val;
end
else begin
op[0] <= op[7];
op[1] <= op[0];
op[2] <= op[1];
op[3] <= op[2];
op[4] <= op[3];
op[5] <= op[4];
op[6] <= op[5];
op[7] <= op[6];
end
end
end
endmodule
for循环:
module lshift_reg (input clk, // Clock input
input rstn, // Active low reset input
input [7:0] load_val, // Load value
input load_en, // Load enable
output reg [7:0] op); // Output register value
integer i;
always @ (posedge clk) begin
if (!rstn) begin
op <= 0;
end
else begin
if (load_en) begin
op <= load_val;
end
else begin
for (i = 0; i < 7; i = i + 1) begin
op[i+1] <= op[i];
end
op[0] <= op[7];
end
end
end
endmodule