Verilog初级教程(15)Verilog中的阻塞与非阻塞语句
文章目录
- 前言
- 正文
- 阻塞赋值
- 非阻塞赋值
- 往期回顾
- 参考资料以及推荐关注
前言
本文通过仿真的方式,形象的说明阻塞赋值以及非阻塞赋值的区别,希望和其他教程相辅相成,共同辅助理解。
正文
阻塞赋值
阻塞赋值语句使用=
进行赋值,并在程序块中一个接一个地执行。但是,这不会阻止在并行块中运行的语句的执行。
通过仿真最容易理解,下面是仿真文件:
module tb;reg [7:0] a, b, c, d, e;initial begina = 8'hDA;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);b = 8'hF1;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);c = 8'h30;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);endinitial begind = 8'hAA;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);e = 8'h55;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);end
endmodule
请注意,当仿真开始时,有两个初始块是并行执行的。语句在每个块中依次执行,两个块在时间0ns处结束。更具体的说,变量a首先被分配,然后是显示语句,接着是所有其他语句。这在输出中可以看到,变量b和c在第一条显示语句中是8’hxx。这是因为当调用第一个$display时,变量b和c的赋值还没有被执行。
打印执行结果:
[0] a=0xda b=0xxx c=0xxx
[0] a=0xda b=0xf1 c=0xxx
[0] a=0xda b=0xf1 c=0x30
[0] d=0xaa e=0xxx
[0] d=0xaa e=0x55
在接下来的例子中,我们将在同一组语句中添加一些延迟,看看它的表现。
module tb;reg [7:0] a, b, c, d, e;initial begina = 8'hDA;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);#10 b = 8'hF1;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);c = 8'h30;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);endinitial begin#5 d = 8'hAA;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);#5 e = 8'h55;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);end
endmodule
仿真记录:
Time resolution is 1 ps
[0] a=0xda b=0xxx c=0xxx
[5000] d=0xaa e=0xxx
[10000] a=0xda b=0xf1 c=0xxx
[10000] a=0xda b=0xf1 c=0x30
[10000] d=0xaa e=0x55
综上,顺序执行或者串行执行一览无余。
非阻塞赋值
非阻塞赋值允许在不阻塞下面语句执行的情况下安排赋值,并由<=
符号指定。值得注意的是,同一个符号在表达式中被用作关系运算符,在非阻塞赋值的上下文中被用作赋值运算符。如果我们以上面的第一个例子为例,将all = symobls
替换为非阻塞赋值操作符<=
,我们会看到输出的结果有一些不同。
module tb;reg [7:0] a, b, c, d, e;initial begina <= 8'hDA;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);b <= 8'hF1;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);c <= 8'h30;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);endinitial begind <= 8'hAA;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);e <= 8'h55;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);end
endmodule
先给出仿真结果:
Time resolution is 1 ps
[0] a=0xxx b=0xxx c=0xxx
[0] a=0xxx b=0xxx c=0xxx
[0] a=0xxx b=0xxx c=0xxx
[0] d=0xxx e=0xxx
[0] d=0xxx e=0xxx
看到所有的$display语句都打印了’h’x。这种行为的原因在于非阻塞赋值的执行方式。特定时间步长的每一条非阻塞语句的RHS都会被捕获,并转入下一条语句。被捕获的RHS值只有在时间步长结束时才会分配给LHS变量。
所以,如果我们把上面例子的执行流程分解一下,我们会得到如下图所示的东西。
注:从前几期可以知道RHS为右值。
|生成块1:初始化
| 时间 #0ns : a <= 8'DA, 为非阻塞,所以记下 RHS (8'hDA) 的值并执行下一步。
| 时间#0ns : $display()阻塞了,所以执行这条语句,但是a还没有收到新的值,所以a=8'hx。
| 时间 #0ns : b <= 8'F1, 为非阻塞,所以记下 RHS 的值 (8'hF1) 并执行下一步。
| 时间#0ns : $display()阻塞,所以执行此语句。但b还没有收到新的值,所以b=8'hx。
| 时间#0ns : c <= 8'30, 非阻塞,所以记下RHS值(8'h30)并执行下一步。
| 时间#0ns : $display()被阻塞,所以执行这条语句,但c还没有收到新的值,所以c=8'hx。
| 时间步骤和初始块结束,将捕获的值分配到变量a、b、c中。
|
|生成块2:初始化
| 时间#0ns : d <= 8'AA, 为非阻塞,所以记下RHS值(8'hAA)并执行下一步。
| 时间#0ns : $display()被阻塞,所以执行这条语句,但d还没有收到新的值,所以d=8'hx。
| 时间#0ns : e <= 8'55, 是非阻塞的,所以记下RHS值(8'h55)并执行下一步。
| 时间#0ns : $display()阻塞,所以执行这条语句,但e没有收到新的值,所以e=8'hx。
| 时间步骤和初始块结束,将捕获的值分配到变量d和e中。
|
|仿真结束在#0ns
接下来,我们用第二个例子,将所有阻塞语句替换成非阻塞语句。
module tb;reg [7:0] a, b, c, d, e;initial begina <= 8'hDA;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);#10 b <= 8'hF1;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);c <= 8'h30;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);endinitial begin#5 d <= 8'hAA;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);#5 e <= 8'h55;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);end
endmodule
恐怕这就有点让人头大了。
给出仿真结果,在进行分析:
Time resolution is 1 ps
[0] a=0xxx b=0xxx c=0xxx
[5000] d=0xxx e=0xxx
[10000] a=0xda b=0xxx c=0xxx
[10000] a=0xda b=0xxx c=0xxx
[10000] d=0xaa e=0xxx
这种仿真结果的意思说明了阻塞赋值的特性,即在当前时刻不立即赋值,只有在一定时间步长结束时才赋值。
上面的例子,在0时刻,执行了如下语句:
a <= 8'hDA;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
由于是非阻塞赋值,所以当前a并不能立即得到右值8’hDA,拿第一个initial为例,在10ns,就得到了这个值8’hda,但是其他值(b和c)仍然为x。
下一个非10ns时刻,我们就可以得到a、b和c的具体值,为了验证,我们添加一条语句:
#1$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
整体程序为:
module assign_tb();reg [7:0] a, b, c, d, e;initial begina <= 8'hDA;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);#10 b <= 8'hF1;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);c <= 8'h30;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);#1$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c); endinitial begin#5 d <= 8'hAA;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);#5 e <= 8'h55;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);end
endmodule
仿真结果:
Time resolution is 1 ps
[0] a=0xxx b=0xxx c=0xxx
[5000] d=0xxx e=0xxx
[10000] a=0xda b=0xxx c=0xxx
[10000] a=0xda b=0xxx c=0xxx
[10000] d=0xaa e=0xxx
[11000] a=0xda b=0xf1 c=0x30
我们主要关注:
[11000] a=0xda b=0xf1 c=0x30
可见,得到了验证。
最后,给出这段非阻塞赋值仿真程序的执行过程:
module tb;reg [7:0] a, b, c, d, e;initial begina <= 8'hDA;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);#10 b <= 8'hF1;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);c <= 8'h30;$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);endinitial begin#5 d <= 8'hAA;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);#5 e <= 8'h55;$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);end
endmodule
|在#0ns处生成Block1:初始化。
| 时间 #0ns : a <= 8'DA, 为非阻塞,所以记下 RHS (8'hDA) 的值并执行下一步。
| 时间#0ns : $display()阻塞了,所以执行这条语句,但是a还没有收到新的值,所以a=8'hx。
| 时间步骤结束:将捕获的值分配给变量a,现在a是8'hDA。
| 等到时间前进10个时间单位到#10ns。
|
| 时间 #10ns : b <= 8'F1, 非阻塞,所以记下 RHS 的值 (8'hF1) 并执行下一步。
|时间#10ns : $display()阻塞,所以执行这条语句。但b还没有收到新的值,所以b=8'hx。
| 时间#10ns : c <= 8'30, 是非阻塞的,所以记下RHS值(8'h30)并执行下一步。
| 时间#10ns : $display()阻塞,所以执行此语句。但是c没有收到新的值,所以c=8'hx。
| 时间步骤和初始块结束,将捕获的值分配到变量b、c中。
|
|在#0ns处生成Block2:初始化。
| 等到时间前进5个时间单位到#5ns。
|
| 时间 #5ns : d <= 8'AA, 为非阻塞,所以记下 RHS 的值 (8'hAA) 并执行下一步。
| 时间#5ns : $display()阻塞,所以执行此语句。但d没有收到新的值,所以d=8'hx。
| 时间步骤结束:将捕获的值分配给变量d,现在d是8'hAA。
| 等到时间前进5个时间单位到#5ns。
|
| 时间#10ns : e <= 8'55, 非阻塞,所以记下RHS值(8'h55)并执行下一步。
| 时间#10ns : $display()阻塞,所以执行这条语句,但e还没有收到新的值,所以e=8'hx。
| 时间步骤和初始块结束,将捕获的值分配给变量e,现在e是8'h55。
|
|仿真结束在#10ns
往期回顾
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?
参考资料以及推荐关注
Verilog Blocking & Non-Blocking
- 个人微信公众号: FPGA LAB
交个朋友
Verilog初级教程(15)Verilog中的阻塞与非阻塞语句相关推荐
- Verilog初级教程(23)Verilog仿真中的显示任务
文章目录 前言 正文 Display/Write Tasks Verilog Strobes Verilog Continuous Monitors Verilog Format Specifiers ...
- Verilog初级教程(21)Verilog中的延迟控制语句
文章目录 前言 正文 延迟控制语句 事件控制语句 Named Events Event or operator 往期回顾 参考资料及推荐关注 前言 Verilog中的延迟控制有两种类型–延迟和事件表达 ...
- Verilog初级教程(20)Verilog中的`ifdef 条件编译语句
文章目录 前言 正文 语法 示例 Testbench文件 往期回顾 参考资料及推荐关注 前言 `ifdef条件编译语句在逻辑设计中还是很常见的,但也常见一些滥用的情况,这应该避免. 应该在什么情况下使 ...
- Verilog初级教程(19)Verilog中的参数
文章目录 前言 正文 模块参数 覆盖参数 例子说明 递增计数器 递减计数器 Specify参数 模块参数与Specify参数的区别 往期回顾 参考资料及推荐关注 前言 Verilog中的参数是使得设计 ...
- Verilog初级教程(16)Verilog中的控制块
文章目录 前言 正文 条件语句if 语法 硬件实现 循环语句 forever repeat while for 往期回顾 参考资料及推荐关注 前言 硬件行为的实现离不开条件语句和其他控制逻辑流的方式. ...
- Verilog初级教程(14)Verilog中的赋值语句
文章目录 前言 正文 合理的左值 过程性赋值(Procedural assignment) 连续赋值 过程连续性赋值 往期回顾 前言 何为赋值语句?即将值放到线网或者变量上,这种操作称为赋值,英文:a ...
- Verilog初级教程(12)Verilog中的generate块
文章目录 前言 正文 generate for generate if generate case 参考资料 本系列博文 前言 verilog中的generate块可以称为生成块,所谓生成,可以理解为 ...
- Verilog初级教程(11)Verilog中的initial块
文章目录 前言 正文 语法格式 initial块是用来干什么的? initial块何时开始又何时结束? 一个模块中允许有多少个initial块? 参考资料 写在最后 前言 仿真中通常会依次执行一组Ve ...
- Verilog初级教程(9)Verilog的运算符
博文目录 写在前面 正文 Verilog算术运算符 Verilog关系运算符 Verilog等价运算符 Verilog逻辑运算符 Verilog位元运算符 Verilog移位运算符 参考资料 交个朋友 ...
最新文章
- 简明python教程购买-简明Python3教程 6.基础
- Linux ipcs命令与ipcrm命令的用法详解
- TensorFlow 笔记5--模型复用
- 手机端展现table_百度信息流广告外包丨百度信息流广告的展现样式和收费方式?...
- 全文检索技术_中药图片拍照识别系统,爬虫、深度学习技术android app 源码分享...
- (组合数学)AtCoder Grand Contest 019 F - Yes or No
- 手摸手,带你用vue撸后台 系列一(基础篇) - 掘金
- mysql数据库引擎InnoDB和MyISAM
- python数据预处理案例_对pandas进行数据预处理的实例讲解
- SQL 对结果集进行分组排序过滤重复数据 ROW_NUMBER
- windows8.1下安装Cygwin并通过apt-cyg安装软件包
- [LeetCode#81]Search in Rotated Sorted Array II
- javaScript this指向问题
- 2021年下半年软考网络工程师真题答案解析
- CentOS配置国内(阿里云)镜像加速器
- 云课堂智慧职教网页版登录入口_智慧职教云课堂登录
- 微信小程序——服务器接口
- python的dbf操作
- 2018年8月27日英语学习
- JZ2440开发板学习------中级(二十七)
热门文章
- 利用autobench测试web服务器极限并发数
- 网管员应掌握好的学习方法
- 选择DataGrid中的CheckBox控件后该行背景变色
- yarn的组成部分_图解YARN工作原理
- viso 画背景框_3分钟漫画教程 | Q版漫画少女线稿,画完暖暖的
- python截取html图片大小,Python打开html文件,截取屏幕截图,裁剪并保存为图像
- php增删改查心得体会,php增删改查入门示例
- oauth过滤login_OAuth2AuthenticationProcessingFilter资源认证服务器过滤器
- react 引入html文件_javascript – React:如何加载和呈现外部html文件?
- bal插口_EBS R12各模块接口表大全