文章目录

  • 前言
  • 正文
    • 条件语句if
      • 语法
      • 硬件实现
    • 循环语句
      • forever
      • repeat
      • while
      • for
  • 往期回顾
  • 参考资料及推荐关注

前言

硬件行为的实现离不开条件语句和其他控制逻辑流的方式。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]) beginMultiple 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]) beginMultiple Statements
end
elseSingle statement

硬件实现

** 没有else的if**

if没有else部分,意味着对于任何不满足if内部表达式的条件,其值保持不变。
保持不变的硬件对应位锁存器,例:

module des (  input en,input d,output reg q);always @ (*)if (en)q = d;endmodule

vivado生成的RTL原理图为:

带有else的if

如果rstn为高电平,输出q将在时钟的上升沿得到输入d的值,并描述了D触发器的行为。

module dff ( input clk,input rstn,input d,output reg q);always @ (posedge clk) beginif (! rstn)q <= 0;elseq <= d;end
endmodule

vivado生成的RTL原理图为:

这个例子中存在一个同步低电平复位,但从上图RTL原理图看出,仍然像是一个异步复位,因为复位信号的输出接到了触发器的rst端,这是什么情况呢?
在刚学习FPGA的时候我就遇到过这个一个问题,也就是综合的原理图(综合的情况应该和RTL原理图一致,只不过使用了某些器件的替换)和硬件语言描述的不一致问题。
这个问题,我看到过一个回答是:

这个回答貌似解决了这个疑问,仅供参考。

为了验证确实是同步复位,也可以通过行为仿真的方式进行验证,这个交给大家去做,由于篇幅有点大,所以赶时间。

if-else-fi

在下面的例子中,设计模块有一个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) beginif (! rstn)q <= 0;else beginif (mode == 1)q <= q + 1;else if (mode == 2)q <= q - 1;endend
endmodule

其原理图为:

如果综合库中有这些元件的话,上面显示的可以认为是综合的输出,值得注意的是,q被实现为一个4位的flop,它有一个CE引脚来使能触发器。值得注意的是,只有当模式为1或2时,这个flop才会被启用,而对于其他值则不会。输出q通过加减器块反馈到同一flop的输入端,通过mux,这也是由模式控制的。

注:综合的输出可能会随着给定技术库中器件的可用性而有所不同。

考虑与上面相同的设计,采用1位模式。

module des ( input mode,input clk,input rstn,output reg [3:0] q);always @ (posedge clk) beginif (! rstn)q <= 0;else beginif (mode)q <= q + 1;elseq <= q - 1;endendendmodule

在这种情况下,一个没有CE引脚的普通触发器与几个多路复用器一起使用,根据模式的值来选择正确的信号。

RTL原理图为:


没有else的if且只有单一语句

module tb;integer a = 10;initial beginif (a == 10)      // if block can have only one statement in it$display ("a is found to be 10");$display ("Always executed regardless of value of a");   // This statement is outside if block becauseend
endmodule

仿真结果:

a is found to be 10
Always executed regardless of value of a

可见if执行后,继续执行if下面的语句。

其他的不再讨论。

循环语句

循环提供了在一个块中执行单个或多个语句一次或多次的方法。在Verilog中,有四种不同类型的循环语句。

forever

这将连续执行块内的语句,不可综合。

forever[statement]forever begin[multiple statements]
end
module my_design;initial beginforever begin$display ("This will be printed forever, simulation can hang ...");endend
endmodule

仿真结果:

This will be printed forever, simulation can hang ...
This will be printed forever, simulation can hang ...
...
...
This will be printed forever, simulation can hang ...
This will be printed forever, simulation can hang ...
This will be printed forever, simulation can hang ...
This will be printed forever, simulation can hang ...
Result reached the maximum of 5000 lines. Killing process.

这条语句常用于仿真中生成时钟信号,例如:

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

repeat

这将执行固定次数的语句。如果表达式的值是X或Z,那么它将被视为零,根本不会被执行。不可综合。

repeat ([num_of_times]) begin[statements]
endrepeat ([num_of_times]) @ ([some_event]) begin[statements]
end
module my_design;initial beginrepeat(4) begin$display("This is a new iteration ...");endend
endmodule

仿真结果:

This is a new iteration ...
This is a new iteration ...
This is a new iteration ...
This is a new iteration ...
ncsim: *W,RNQUIE: Simulation is complete.

while

只要表达式为真,就会执行语句,一旦条件为假,就会退出。如果条件从一开始就是假的,则根本不会执行语句。不可综合。

while (expression) begin[statements]
end
module my_design;integer i = 5;initial beginwhile (i > 0) begin$display ("Iteration#%0d", i);i = i - 1;endend
endmodule

仿真结果:

Iteration#5
Iteration#4
Iteration#3
Iteration#2
Iteration#1
ncsim: *W,RNQUIE: Simulation is complete.

for

for循环是软件中使用最广泛的循环,但它主要用于复制Verilog中的硬件逻辑。for循环背后的思想是,只要给定的条件为真,就对循环内给定的一组语句进行迭代。这与while循环非常相似,但更多的是用在有迭代器的情况下,条件取决于这个迭代器的值。

for (<initial_condition>; <condition>; <step_assignment>) begin// Statements
end

这将使用一个三步走的过程来控制语句。

  • 初始化一个循环计数器变量
  • 计算表达式,通常涉及循环计数器变量
  • 增加循环计数器变量,这样在以后的时间里,表达式会变成假的,循环会退出。

或者:

  • 初始条件指定信号的初始值
  • 用于评估给定条件是否为真的检查。
  • 更新下一次迭代的控制变量

注:这里的增加循环计算器变量不能受到C语言影响,使用i++或者++i之类的,要使用i = i + 1等。

初始条件和控制变量的更新都包含在for循环中,与while循环不同,不需要单独指定。while循环是更通用的,大多数情况下,只有当给定条件下的语句需要重复使用时才会使用。然而for循环的开头和结尾都是明确的,由步骤变量控制。

module my_design;integer i = 5;initial beginfor (i = 0; i < 5; i = i + 1) begin$display ("Loop #%0d", i);endend
endmodule

仿真结果:

Loop #0
Loop #1
Loop #2
Loop #3
Loop #4
ncsim: *W,RNQUIE: Simulation is complete.

注:for循环使用得当,是可以综合的。

让我们看看在Verilog中如何在没有for循环的情况下实现8位左移位寄存器,然后与使用for循环的代码进行比较,以体会循环结构的效用。

module lshift_reg (input                         clk,                // Clock inputinput                         rstn,               // Active low reset inputinput [7:0]            load_val,   // Load valueinput                      load_en,        // Load enableoutput reg [7:0] op);                 // Output register value// At posedge of clock, if reset is low set output to 0// If reset is high, load new value to op if load_en=1// If reset is high, and load_en=0 shift register to leftalways @ (posedge clk) beginif (!rstn) beginop <= 0;end else beginif (load_en) beginop <= load_val;end else beginop[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];endendend
endmodule

同样的行为可以使用for循环来实现,这将减少代码,并使其对不同的寄存器宽度具有可扩展性。如果将寄存器的宽度作为Verilog参数,设计模块将变得可扩展,同样的参数可以在for循环里面使用。

module lshift_reg (input                         clk,                // Clock inputinput                 rstn,               // Active low reset inputinput [7:0]            load_val,   // Load valueinput                      load_en,        // Load enableoutput reg [7:0] op);                 // Output register valueinteger i;// At posedge of clock, if reset is low set output to 0// If reset is high, load new value to op if load_en=1// If reset is high, and load_en=0 shift register to leftalways @ (posedge clk) beginif (!rstn) beginop <= 0;end else begin// If load_en is 1, load the value to op// else keep shifting for every clockif (load_en) beginop <= load_val;end else beginfor (i = 0; i < 7; i = i + 1) beginop[i+1] <= op[i];endop[0] <= op[7];endendend
endmodule

可见,针对移位寄存器,使用for循环方便很多,但是下面这种写法会不会更好理解呢?

module lshift_reg (input                         clk,                // Clock inputinput                 rstn,               // Active low reset inputinput [7:0]            load_val,   // Load valueinput                      load_en,        // Load enableoutput reg [7:0] op);                 // Output register valueinteger i;// At posedge of clock, if reset is low set output to 0// If reset is high, load new value to op if load_en=1// If reset is high, and load_en=0 shift register to leftalways @ (posedge clk) beginif (!rstn) beginop <= 0;end else begin// If load_en is 1, load the value to op// else keep shifting for every clockif (load_en) beginop <= load_val;end else beginop[0] <= op[7];op[7:1] <= op[6:0];/*op <= {op[6:0],op[7]};/*endendend
endmodule

往期回顾

Verilog初级教程(15)Verilog中的阻塞与非阻塞语句

Verilog初级教程(14)Verilog中的赋值语句

Verilog初级教程(13)Verilog中的块语句

Verilog初级教程(12)Verilog中的generate块

Verilog初级教程(11)Verilog中的initial块

Verilog初级教程(10)Verilog的always块

Verilog初级教程(9)Verilog的运算符

Verilog初级教程(8)Verilog中的assign语句

Verilog初级教程(7)Verilog模块例化以及悬空端口的处理

Verilog初级教程(6)Verilog模块与端口

Verilog初级教程(5)Verilog中的多维数组和存储器

Verilog初级教程(4)Verilog中的标量与向量

Verilog初级教程(3)Verilog 数据类型

Verilog初级教程(2)Verilog HDL的初级语法

Verilog初级教程(1)认识 Verilog HDL

芯片设计抽象层及其设计风格

Verilog以及VHDL所倡导的的代码准则

FPGA/ASIC初学者应该学习Verilog还是VHDL?

参考资料及推荐关注

ii-else-if

for-loop

verilog-control-block

移位寄存器

个人微信公众号: FPGA LAB

交个朋友

Verilog初级教程(16)Verilog中的控制块相关推荐

  1. Verilog初级教程(23)Verilog仿真中的显示任务

    文章目录 前言 正文 Display/Write Tasks Verilog Strobes Verilog Continuous Monitors Verilog Format Specifiers ...

  2. Verilog初级教程(21)Verilog中的延迟控制语句

    文章目录 前言 正文 延迟控制语句 事件控制语句 Named Events Event or operator 往期回顾 参考资料及推荐关注 前言 Verilog中的延迟控制有两种类型–延迟和事件表达 ...

  3. Verilog初级教程(20)Verilog中的`ifdef 条件编译语句

    文章目录 前言 正文 语法 示例 Testbench文件 往期回顾 参考资料及推荐关注 前言 `ifdef条件编译语句在逻辑设计中还是很常见的,但也常见一些滥用的情况,这应该避免. 应该在什么情况下使 ...

  4. Verilog初级教程(19)Verilog中的参数

    文章目录 前言 正文 模块参数 覆盖参数 例子说明 递增计数器 递减计数器 Specify参数 模块参数与Specify参数的区别 往期回顾 参考资料及推荐关注 前言 Verilog中的参数是使得设计 ...

  5. Verilog初级教程(15)Verilog中的阻塞与非阻塞语句

    文章目录 前言 正文 阻塞赋值 非阻塞赋值 往期回顾 参考资料以及推荐关注 前言 本文通过仿真的方式,形象的说明阻塞赋值以及非阻塞赋值的区别,希望和其他教程相辅相成,共同辅助理解. 正文 阻塞赋值 阻 ...

  6. Verilog初级教程(14)Verilog中的赋值语句

    文章目录 前言 正文 合理的左值 过程性赋值(Procedural assignment) 连续赋值 过程连续性赋值 往期回顾 前言 何为赋值语句?即将值放到线网或者变量上,这种操作称为赋值,英文:a ...

  7. Verilog初级教程(12)Verilog中的generate块

    文章目录 前言 正文 generate for generate if generate case 参考资料 本系列博文 前言 verilog中的generate块可以称为生成块,所谓生成,可以理解为 ...

  8. Verilog初级教程(11)Verilog中的initial块

    文章目录 前言 正文 语法格式 initial块是用来干什么的? initial块何时开始又何时结束? 一个模块中允许有多少个initial块? 参考资料 写在最后 前言 仿真中通常会依次执行一组Ve ...

  9. Verilog初级教程(9)Verilog的运算符

    博文目录 写在前面 正文 Verilog算术运算符 Verilog关系运算符 Verilog等价运算符 Verilog逻辑运算符 Verilog位元运算符 Verilog移位运算符 参考资料 交个朋友 ...

最新文章

  1. 微软小冰作词又作曲,网友:要出道的节奏吗?
  2. Microbiome:地球上有多大比例的原核生物已经被测序了基因组?
  3. Python 百度面试题
  4. java doc转pdf_java 完美解决 ppt/pptx 转pdf 源码
  5. 17个服务器发展趋势,我们都给您总结好了!
  6. [2018HN省队集训D8T1] 杀毒软件
  7. [react] 怎么在React中引入其它的UI库,例如Bootstrap
  8. android实现10ms定时器,Android三种实现定时器的方法
  9. 简单python脚本实例-python常用运维脚本实例
  10. 创建CocoaPods的Framework Swift组件化之路(上)
  11. java中socket编程实例_Java Socket编程实例
  12. 微信ubuntu版服务器,Ubuntu 18.04 安装微信(Linux通用)
  13. java全能速查宝典_MATLAB函数全能速查宝典 邓薇等 编著.pdf
  14. 各省省际对外非金融类直接投资流量情况(2009-2018年)
  15. 使用WebUploader实现图片上传
  16. Keil(C51)安装与注册
  17. 论文阅读:FFA-Net: Feature Fusion Attention Network for Single Image Dehazing
  18. 思必驰DUI集成指南
  19. 2018医疗器械行业发展
  20. python特殊符号怎么打_Python显示特殊字符

热门文章

  1. 复古人像黑白照片PS后期处理PS插件_安装教程
  2. 获得淘宝/天猫app商品详情原数据
  3. 【图形学】Bézier 曲面建模及显示
  4. 苹果id登录_手机小技巧公众号:iPhone忘记ID密码怎么办?不花钱,这波操作帮你轻松解决...
  5. 轻量级深度学习网络——MobileNet MobileNet v2
  6. BCS2022成果发布:奇安信首次展示“零事故”背后“软实力”
  7. 非智能手机java_JAVA非智能手机:三普手机功能优缺点介绍
  8. 关于腾讯这道数组面试题,这可能是最笨的解法
  9. videojs重播_nginx搭建流媒体服务器,实现点播,直播,转播,录播(直播回放)功能(未完)...
  10. java oracle分页查询语句_Oracle分页查询语句的写法(转)