jjzjj

Verilog Tutorial(8)循环语句

孤独的单刀 2023-04-19 原文

写在前面

在自己准备写verilog教程之前,参考了许多资料----FPGA Tutorial网站的这套verilog教程即是其一。这套教程写得不错,只是没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。

这是网站原文:https://fpgatutorial.com/verilog/

这是系列导航:Verilog教程系列文章导航


这篇文章将讨论可以在 verilog 中使用的不同类型的循环语句----for循环、while循环、foever循环和repeat循环。

正如之前文章中描述的那样,有许多语句只能在过程块中使用,这些语句被用来控制在 verilog 设计中给数据赋值。类似的,在 verilog 中使用的四种不同类型的循环语句也是用来在设计中赋值的顺序语句。因此只能在过程块内编写循环,例always块或initial块。

Verilog 中的循环

设计者可以在 verilog 中使用循环语句来多次执行相同的代码。最常用的循环语句是for循环----使用此循环将一段代码执行固定次数

设计者还可以在 verilog 中使用repeat循环----它与 for 循环功能类似

在 verilog 中常用的另一种循环是while循环,只要给定条件为真,此循环就会执行特定代码。

Verilog Forever循环

verilog 中的forever循环会创建一个连续执行的代码块,就像其他编程语言中的无限循环一样。这与 verilog 中的其他类型的循环形成对比,例如 for 循环和 while 循环,它们就只会运行固定的次数

forever循环最常见的用法是在testbench生成时钟信号forever循环无法被综合,这意味着只能在testbench中使用它。

下面的代码片段展示了 forever语句的一般语法。

forever begin
    // 这里写要被循环执行的语句
end

示例

为了更好地演示如何在实践中使用forever循环,请看这个示例----生成一个频率为 10MHz 的时钟信号,以在testbench中使用它。

首先为信号赋初始值,使用 forever 语句定期翻转信号。下面的代码片段展示如何在实现这个时钟。

initial begin
   clk = 1'b0;
   forever begin
     #500 clk = ~clk;
   end
end

首先,请注意示例中使用了verilog中的initial块,这是过程语句的一个示例。在initial块中编写的任何代码都会在仿真开始时执行一次。在testbench代码中使用的几乎都是initial块而不是always块。这样做的原因是它们只执行一次,而仿真通常只需要运行一次。

要注意的另一件重要事情是使用 # 符号来实现时间延迟。为了让这个例子正常工作,需要在代码中包含timescale编译指令----来指定仿真的时间单位和精度

在此示例中时间单位被设置为 ns而精度被设置为 ps,如下面的代码片段所示。

`timescale 1ns / 1ps

Verilog Repeat循环

repeat循环将会给特定的 verilog 代码块执行指定的次数

虽然repeat循环在testbench中最为常见,但设计者也可以在可综合的代码中使用它。但是,在使用这种语句来构造可综合代码时必须小心,因为其只能被用来描述重复结构。

下面的代码片段展示了repeat循环的一般语法。

repeat (<number>) begin    //指定重复次数
    //需要重复执行的代码
end

<number> 用来确定重复循环的次数。repeat 循环与 for 循环非常相似,因为它们都将代码重复固定次数

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

相反,repeat 循环则不包括这个局部变量。所以在不需要这个变量的情况下,repeat 循环实际上比 for 循环更简洁。

示例

接下来将用一个简单示例来演示其具体用法----假设设计中有一个信号,而设计中的另一个信号则在该信号出现上升沿时翻转,这个翻转总共只实现6次

下面的波形展示了在此示例中要实现的功能。

对应的代码如下所示。

repeat (6) begin      //重复6次
  @(posedge sig_a)    //上升沿
      sig_b = ~sig_b; //翻转
end

在这个例子中可以看到, <number> 参数被设置为 6。因此,repeat循环将在终止之前总共运行六次。

在 verilog 中,@ 符号被用实现wait event,这意味着代码将在此行暂停并等待括号中的条件评估为----一旦发生代码将继续运行。在此示例中,此运算符被用来阻止repeat循环的执行,直到在 sig_a 信号上检测到上升沿。

最后,只要检测到上升沿,就可以使用 not这个位运算符(~)来翻转信号。

下面的波形展示这段代码的仿真结果。

Verilog While 循环

在while循环的每次迭代之前都会判断指定的条件,只要给定条件为,while 循环就会执行条件内的verilog 代码;反之则不会执行

while 循环类似一个重复执行的if语句。由于 while 循环通常不可被综合,所以经常在testbench使用它来生成测试激励。

下面的代码片段展示了 verilog 中 while 循环的一般语法。

while <condition> begin    //判断条件
  // Code to execute       //要重复执行的语句
end

<condition> 用来来确定循环何时执行和何时停止

示例

为了更好地演示如何在 verilog 中使用 while 循环,接下来将用一个简单示例来演示其具体用法----创建一个从 0 到 3 的integer型变量,然后在循环的每次迭代中打印这个变量的值。

下面的代码片段展示了如何实现这个例子。

while (iter < 4) begin
  $display("iter = %0d", iter);
  iter = iter + 1;
end

这个例子假设 iter 变量已经被声明并赋了一个初始值 0。在循环的每次迭代中,循环体内代码的第二行都使 iter 变量+1。此示例中的 <condition> 参数被设置为仅当 iter 变量小于 4 时才执行循环。因此,此循环中 iter 变量将从 0 递增到 3。

$display 被用来在循环的每次迭代中打印 iter 变量的值,%0d 运算符指示变量应打印为十进制数。

Verilog For循环

for 循环会将一段代码执行固定次数,与 while 循环一样,只要给定条件为,for 循环就会执行。将此条件将被指定为 for 循环声明的一部分,用于控制循环执行的次数。

虽然它通常用于testbench,但也可以在可综合的 verilog 代码中使用 for 循环。在可综合的代码中使用 for 循环时,通常使用它来复制硬件,最常见的例子之一是移位寄存器。

正如之前提到的,for 循环与 repeat 循环非常相似。主要区别在于 for 循环使用了一个局部变量,它可以在循环代码中使用。

下面的代码片段展示了在 verilog中for 循环的一般语法。

for (<initial_condition>; <stop_condition>; <increment>) begin    //执行条件判断
  //要循环执行的代码
end

<initial_condition> 用来设置循环变量的初始值。在使用它之前,必须先声明将在循环中使用的局部变量。

<stop_condition> 用来确定循环运行次数的条件语句。for 循环将继续执行,直到该字段被判断为 false。

<increment> 用来确定在循环的每次迭代中如何更新循环变量。

示例

为了更好地演示如何在 verilog 中使用 for 循环,接下来将用一个简单示例来演示其具体用法----一个简单的4位串行移位寄存器。

实现移位寄存器实际上是 for 循环最常见的用例之一----可以使用一个简单的verilog数组来实现。首先将移位寄存器的输入赋值给数组的第一个元素,然后使用 for 循环将数组整体向左移动一位

下面的 verilog 代码片段展示了如何使用 for 循环实现此移位寄存器。

//将输入赋值给数组的第一个数
shift[0] <= circuit_in;

//使用for循环语句来将数组整体向左移动
for (i = 1; i < 4; i = i + 1) begin
  shift[i] <= shift[i-1];
end

在此代码中首先要注意的是,循环变量 (i) 被用来引用循环中的数组元素。在中使用它之前,必须先声明这个循环变量。由于移位数组有四位,因此设置了 <stop_condition>小于4,以便仅当循环变量 (i) 小于4时才执行循环。最后,设置了 <increment> 字段以使循环变量在每次迭代中都增加 1----这允许代码遍历数组中的每个元素。

在这个例子中使用了非阻塞赋值,这是因为移位寄存器是时序逻辑电路的一个典型例子。因此必须在时钟控制的verilog always块中编写此代码才能正确实现移位寄存器。


  • 📣您有任何问题,都可以在评论区和我交流📃

  • 📣您的支持是我持续创作的最大动力!如果本文对您有帮助,还请多多点赞👍、评论💬和收藏


有关Verilog Tutorial(8)循环语句的更多相关文章

  1. ruby - 树顶语法无限循环 - 2

    我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He

  2. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  3. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  4. ruby - 如何在 Ruby 中向现有方法定义添加语句 - 2

    我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca

  5. ruby - ruby 乘法语句中星号中断语法前的空格 - 2

    在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl

  6. ruby - 有没有办法从 ruby​​ case 语句中访问表达式? - 2

    我想从then子句中访问c​​ase语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案

  7. ruby - Ruby 中的闭包和 for 循环 - 2

    我是Ruby的新手,有些闭包逻辑让我感到困惑。考虑这段代码:array=[]foriin(1..5)array[5,5,5,5,5]这对我来说很有意义,因为i被绑定(bind)在循环之外,所以每次循环都会捕获相同的变量。使用每个block可以解决这个问题对我来说也很有意义:array=[](1..5).each{|i|array[1,2,3,4,5]...因为现在每次通过时都单独声明i。但现在我迷路了:为什么我不能通过引入一个中间变量来修复它?array=[]foriin1..5j=iarray[5,5,5,5,5]因为j每次循环都是新的,我认为每次循环都会捕获不同的变量。例如,这绝对

  8. ruby - 在 Ruby 的 if 语句中检查 bash 命令 - 2

    如何在Ruby的if语句中检查bash命令的返回值(true/false)。我想要这样的东西,if("/usr/bin/fswscell>/dev/null2>&1")has_afs="true"elsehas_afs="false"end它会提示以下错误含义,它总是返回true。(irb):5:warning:stringliteralincondition正确的语法是什么?更新:/usr/bin/fswscell寻找afs安装和运行状态。它会抛出这样的字符串,Thisworkstationbelongstocell如果afs没有运行,命令以状态1退出 最

  9. ruby - 变量赋值后的 if 语句 - 有多常见? - 2

    我最近与一位同事讨论了以下Ruby语法:value=ifa==0"foo"elsifa>42"bar"else"fizz"end我个人并没有看到太多这种逻辑,但我的同事指出,这实际上是一种相当普遍的Rubyism。我试着用谷歌搜索这个主题,但没有找到任何文章、页面或SO问题来讨论它,这让我相信这可能是一种非常实际的技术。然而,另一位同事发现语法令人困惑,而是将上面的逻辑写成这样:ifa==0value="foo"elsifa>42value="bar"elsevalue="fizz"end缺点是value=的重复声明和隐式elsenil的丢失,如果我们想使用它的话。这也感觉它与Ruby

  10. ruby - 当你有一个没有参数的 case 语句并且 when 子句是 lambda 时会发生什么? - 2

    这段代码没有像我预期的那样执行:casewhen->{false}then"why?"else"ThisiswhatIexpect"end#=>"why?"这也不是casewhen->(x){false}then"why?"else"ThisiswhatIexpect"end#=>"why?"第一个then子句在两种情况下都被执行,这意味着我提供给when子句的lambda没有被调用。我知道无论when子句的主题是什么,都应该调用大小写相等运算符===。我想知道当没有为case提供参数时,===的另一边会发生什么。我在想它可能是nil,但它不可能是:->{false}===nil#=>

随机推荐