FPGA的设计艺术(15)逻辑设计及仿真利器之各式各样的循环

举报
李锐博恩 发表于 2021/08/25 23:18:09 2021/08/25
【摘要】 前言 Verilog中的循环各式各样,例如,for循环,while循环,forever循环和repeat循环,有的可以综合有的不可用综合,就凭这一条特点,就能在逻辑设计中排除很多种循环语句,对于设计来说...

前言

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

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。