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

李锐博恩 2021-03-17 23:24:53 5371

前言

Verilog中的循环各式各样,例如,for循环,while循环,forever循环和repeat循环,有的可以综合有的不可用综合,就凭这一条特点,就能在逻辑设计中排除很多种循环语句,对于设计来说,只能用可以综合的循环语句,例如for循环语句。那么既然只有for等循环可以综合,那么其他循环语句存在的意义在哪里呢?

当然是仿真啦,仿真可没有要求Verilog可综合,只要是Verilog中的语法,都可以使用。但一般而言,我们也使用不了那么多,因为很多循环作用都是一样的,我们可根据自己的喜欢来使用。例如对于时钟生成来说,有人习惯于:

initial begin
    clk = 0;
    forever begin
        #5 clk = ~clk;
    end
end

有人习惯于:

initial begin
clk = 0;
end

always begin
    #5 clk = ~clk;
end

当然,你用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
forever循环例子

为了更好地演示我们如何在实践中使用永久循环,让我们考虑一个示例。

在此示例中,我们将生成一个频率为10MHz的时钟信号(100ns周期),可以在测试台内部使用。

为此,我们首先将信号分配给初始值。然后,我们使用forever块以固定的时间间隔反转信号。

下面的代码片段显示了我们如何在verilog中实现此时钟示例。

initial begin

   clk = 1'b0;

   forever begin

     #50 clk = ~clk;

   end

 end

关于此示例有两点要说的重要事情。

首先,请注意,我们使用verilog初始块,这是过程语句的另一个示例。我们在初始块中编写的任何代码在仿真开始时都会执行一次。

我们几乎总是在testbench代码中使用initial块,而不是always使用块。原因是它们只执行一次,而我们通常只需要运行一次测试。

这里要注意的另一个重要事项是使用#符号来仿真verilog中的时间延迟。

为了使此示例正常工作,我们需要在代码中包含verilog timescale编译器指令。

我们使用timescale编译器指令来指定仿真的时间单位和分辨率。

在这种情况下,我们需要将时间单位设置为ns,如下面的代码片段所示。

`timescale 1ns / 1ps
Verilog repeat循环

我们使用重复循环以固定次数执行给定的Verilog代码块。

我们在重复循环声明中指定代码块将执行的次数。

尽管我们最常在verilog测试平台中使用重复循环,但也可以在可综合代码中使用它。

但是,在使用此结构可综合代码时,我们必须小心,只能使用它来描述重复结构。

下面的代码段显示了Verilog重复循环的一般语法

repeat (<number>) begin

  // Code to be executed in the loop

end

我们使用字段来确定重复循环执行了多少次。

repeat循环与verilog中的for循环非常相似,因为它们都执行固定次数的代码。

这两种类型的循环之间的主要区别在于,for循环包含一个局部变量,我们可以在循环内部引用该局部变量。该变量的值在循环的每次迭代中更新。

相反,repeat循环不包含此局部循环变量。结果,在不需要此变量的情况下,repeat循环实际上比for循环更简洁。

repeat循环示例

重复循环是一个相对简单的构造。但是,让我们考虑一个基本示例,以更好地演示其工作原理。

对于此示例,假设我们的设计中有一个信号,只要我们的设计中的另一个信号有上升沿,我们都希望切换。

下面的波形显示了我们在此示例循环中试图实现的功能。

波形表示sig_b信号每次在sig_a信号上出现上升沿时都会反转。
但是,我们只希望此切换操作总共有效六次。

我们可以在重复块中轻松实现这一点,如下面的代码片段所示。

repeat (6) begin

  @(posedge sig_a)

  sig_b = ~sig_b;

end

在此示例中,我们可以看到将字段设置为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

我们在上述结构中使用字段来确定何时停止执行循环。

while循环示例

为了更好地演示我们如何在verilog中使用while循环,让我们考虑一个基本示例。

对于此示例,我们将创建一个整数类型变量,该变量将从0增加到3。然后,在循环的每次迭代中打印此变量的值。

尽管这是一个简单的示例,但它演示了while循环的基本原理。

下面的代码段显示了我们如何实现此示例。

while (iter < 4) begin

  $display("iter = %0d", iter);

  iter = iter + 1;

end

本示例假定iter变量已经被声明并分配了初始值0。

在循环的每次迭代中,循环体内代码的第二行都会增加iter变量。

设置本示例中的condition字段,以便仅在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

我们使用字段设置循环变量的初始值。必须先声明在循环中使用的变量,然后才能在代码中使用它。

字段是条件语句,它确定循环运行多少次。for循环将继续执行,直到该字段的值为假。 我们使用字段来确定在循环的每次迭代中如何更新循环变量。 #### Verilog for循环示例 为了更好地演示我们如何在Verilog中使用for循环,让我们考虑一个基本示例。 对于此示例,我们将使用verilog for循环编写一个简单的四位串行移位寄存器。实际上,实现移位寄存器实际上是for循环的最常见用例之一。 移位寄存器可以使用简单的Verilog数组实现。 然后,我们可以将输入到移位寄存器的内容分配给数组的第一个元素。然后,我们使用for循环将数组的现有内容向左移动一位。 下面的Verilog代码片段显示了如何使用for循环实现此移位寄存器。 ```c // 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 ``` 此代码中要注意的第一件事是,我们使用循环变量(i)在循环中引用数组的元素。我们必须先声明此循环变量,然后才能在代码中使用它。 由于我们的移位数组有四个位,因此我们设置了stop_condition字段,以便仅在循环变量(i)小于四时才执行循环。 最后,我们设置increment字段,以使循环变量在每次迭代中都加1。这使我们可以遍历数组中的每个元素。
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 96 8 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
李锐博恩
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区