FPGA的设计艺术(15)逻辑设计及仿真利器之各式各样的循环
前言
Verilog中的循环各式各样,例如,for循环,while循环,forever循环和repeat循环,有的可以综合有的不可用综合,就凭这一条特点,就能在逻辑设计中排除很多种循环语句,对于设计来说,只能用可以综合的循环语句,例如for循环语句。那么既然只有for等循环可以综合,那么其他循环语句存在的意义在哪里呢?
当然是仿真啦,仿真可没有要求Verilog可综合,只要是Verilog中的语法,都可以使用。但一般而言,我们也使用不了那么多,因为很多循环作用都是一样的,我们可根据自己的喜欢来使用。例如对于时钟生成来说,有人习惯于:
initial begin
clk = 0;
forever begin
#5 clk = ~clk;
end
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
有人习惯于:
initial begin
clk = 0;
end
always begin
#5 clk = ~clk;
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
当然,你用for循环也没人说你不对。
下面,我们讨论在verilog中如何使用每个循环。然后,我们为这些结构中的每一个考虑一个简短的示例,以说明我们如何在实践中使用它们。
Verilog中的循环
我们在verilog中使用循环来多次执行相同的代码。
Verilog中最常用的循环是for循环。我们使用此循环执行代码块固定次数。
我们还可以在verilog中使用repeat关键字,该关键字执行与for循环相似的功能。但是,在Verilog设计中,我们通常更喜欢使用for循环而不是repeat关键字。
我们在Verilog中通常使用的另一种循环是while循环。只要给定条件为真,我们就使用此循环执行部分代码。
让我们仔细看一下每种循环类型。
Verilog forever循环
我们在verilog中使用forever循环创建代码块,该代码块将连续执行,就像其他编程语言中的无限循环一样。
这与Verilog中其他类型的循环(例如for循环和while循环)相反,后者仅运行固定次数。
正如我们在之前关于verilog测试平台的帖子中看到的那样,forever循环最常见的用例之一是在verilog测试平台中生成时钟信号。
forever循环无法综合,这意味着我们只能在测试基准代码中使用它。
下面的代码片段显示了verilog forever循环的常规语法。
forever begin
// Code to be executed by the loop goes here
end
- 1
- 2
- 3
- 4
- 5
forever循环例子
为了更好地演示我们如何在实践中使用永久循环,让我们考虑一个示例。
在此示例中,我们将生成一个频率为10MHz的时钟信号(100ns周期),可以在测试台内部使用。
为此,我们首先将信号分配给初始值。然后,我们使用forever块以固定的时间间隔反转信号。
下面的代码片段显示了我们如何在verilog中实现此时钟示例。
initial begin
clk = 1'b0;
forever begin
#50 clk = ~clk;
end
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
关于此示例有两点要说的重要事情。
首先,请注意,我们使用verilog初始块,这是过程语句的另一个示例。我们在初始块中编写的任何代码在仿真开始时都会执行一次。
我们几乎总是在testbench代码中使用initial块,而不是always使用块。原因是它们只执行一次,而我们通常只需要运行一次测试。
这里要注意的另一个重要事项是使用#符号来仿真verilog中的时间延迟。
为了使此示例正常工作,我们需要在代码中包含verilog timescale编译器指令。
我们使用timescale编译器指令来指定仿真的时间单位和分辨率。
在这种情况下,我们需要将时间单位设置为ns,如下面的代码片段所示。
`timescale 1ns / 1ps
- 1
Verilog repeat循环
我们使用重复循环以固定次数执行给定的Verilog代码块。
我们在重复循环声明中指定代码块将执行的次数。
尽管我们最常在verilog测试平台中使用重复循环,但也可以在可综合代码中使用它。
但是,在使用此结构可综合代码时,我们必须小心,只能使用它来描述重复结构。
下面的代码段显示了Verilog重复循环的一般语法
repeat (<number>) begin
// Code to be executed in the loop
end
- 1
- 2
- 3
- 4
- 5
我们使用字段来确定重复循环执行了多少次。
repeat循环与verilog中的for循环非常相似,因为它们都执行固定次数的代码。
这两种类型的循环之间的主要区别在于,for循环包含一个局部变量,我们可以在循环内部引用该局部变量。该变量的值在循环的每次迭代中更新。
相反,repeat循环不包含此局部循环变量。结果,在不需要此变量的情况下,repeat循环实际上比for循环更简洁。
repeat循环示例
重复循环是一个相对简单的构造。但是,让我们考虑一个基本示例,以更好地演示其工作原理。
对于此示例,假设我们的设计中有一个信号,只要我们的设计中的另一个信号有上升沿,我们都希望切换。
下面的波形显示了我们在此示例循环中试图实现的功能。
波形表示sig_b信号每次在sig_a信号上出现上升沿时都会反转。
但是,我们只希望此切换操作总共有效六次。
我们可以在重复块中轻松实现这一点,如下面的代码片段所示。
repeat (6) begin
@(posedge sig_a)
sig_b = ~sig_b;
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
在此示例中,我们可以看到将字段设置为6。因此,重复循环将在终止之前总共运行六次。
然后,我们在Verilog上always块的帖子中讨论的posege宏。该宏告诉我们代码中的sig_a信号何时出现上升沿。
在verilog中,我们使用@符号告诉我们的代码等待事件发生。
这仅表示代码将在此行暂停,并等待方括号中的条件评估为true。一旦发生这种情况,代码将继续运行。
在此示例中,我们使用此运算符阻止重复循环的执行,直到在sig_a信号上检测到上升沿为止。
最后,只要检测到上升沿,就可以使用非Verilog逐位运算符(〜)将sig_b信号反相。
下面的波形显示了此代码的仿真结果:
仿真输出显示,每次在名为sig_a的信号上出现上升沿时,就会将名为sig_b的信号反转。
Verilog while循环
只要给定条件为真,我们就使用while循环执行部分Verilog代码。
在循环的每次迭代之前都会评估指定的条件。
结果,该块中的所有代码将在每次有效迭代中执行。
即使条件发生了变化,以致在块中的代码运行时,它的求值结果不再为true,也会发生这种情况。
我们可以将while循环视为重复执行的if语句。
由于虽然通常无法综合循环,所以我们经常在测试台中使用它们来产生刺激。
下面的代码段显示了verilog中while循环的常规语法。
while <condition> begin
// Code to execute
end
- 1
- 2
- 3
- 4
- 5
我们在上述结构中使用字段来确定何时停止执行循环。
while循环示例
为了更好地演示我们如何在verilog中使用while循环,让我们考虑一个基本示例。
对于此示例,我们将创建一个整数类型变量,该变量将从0增加到3。然后,在循环的每次迭代中打印此变量的值。
尽管这是一个简单的示例,但它演示了while循环的基本原理。
下面的代码段显示了我们如何实现此示例。
while (iter < 4) begin
$display("iter = %0d", iter);
iter = iter + 1;
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
本示例假定iter变量已经被声明并分配了初始值0。
在循环的每次迭代中,循环体内代码的第二行都会增加iter变量。
设置本示例中的字段,以便仅在iter变量小于4时才执行循环。结果,在此循环中,iter变量从0递增到3。
Verilog For循环
在编写Verilog代码时,我们使用for循环以固定次数执行代码块。
与while循环一样,只要给定条件为true,for循环就会执行。在循环的每次迭代之前都会评估指定的条件。
我们将此条件指定为for循环声明的一部分。此条件用于控制循环执行的次数。
尽管它通常在测试平台中使用,但我们也可以在可综合的Verilog代码中使用for循环。
当我们在可综合代码中使用for循环时,通常会使用它来复制硬件的各个部分。最常见的例子之一是移位寄存器。
如前所述,for循环与repeat循环非常相似。主要区别在于for循环使用可以在我们的循环代码中使用的局部变量。
下面的代码段显示了我们在verilog for循环中使用的语法。
for (<initial_condition>; <stop_condition>; <increment>) begin
// Code to execute
end
- 1
- 2
- 3
- 4
- 5
我们使用<initial_condition>字段设置循环变量的初始值。必须先声明在循环中使用的变量,然后才能在代码中使用它。
<stop_condition>字段是条件语句,它确定循环运行多少次。for循环将继续执行,直到该字段的值为假。
我们使用字段来确定在循环的每次迭代中如何更新循环变量。
Verilog for循环示例
为了更好地演示我们如何在Verilog中使用for循环,让我们考虑一个基本示例。
对于此示例,我们将使用verilog for循环编写一个简单的四位串行移位寄存器。实际上,实现移位寄存器实际上是for循环的最常见用例之一。
移位寄存器可以使用简单的Verilog数组实现。
然后,我们可以将输入到移位寄存器的内容分配给数组的第一个元素。然后,我们使用for循环将数组的现有内容向左移动一位。
下面的Verilog代码片段显示了如何使用for循环实现此移位寄存器。
// The circuit input goes into the first register
shift[0] = circuit_in;
// A for loop to shift the contents of the register
for (i = 1; i < 4; i = i + 1) begin
shift[i] = shift[i-1];
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
此代码中要注意的第一件事是,我们使用循环变量(i)在循环中引用数组的元素。我们必须先声明此循环变量,然后才能在代码中使用它。
由于我们的移位数组有四个位,因此我们设置了<stop_condition>字段,以便仅在循环变量(i)小于四时才执行循环。
最后,我们设置字段,以使循环变量在每次迭代中都加1。这使我们可以遍历数组中的每个元素。
文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。
原文链接:reborn.blog.csdn.net/article/details/114804987
- 点赞
- 收藏
- 关注作者
评论(0)