芯航线——普利斯队长精心奉献

 

实验目的:掌握阻塞赋值与非阻塞赋值的区别

实验平台:无

实验原理:

    阻塞赋值,操作符为"=","阻塞"是指在进程语句(initial和always)中,当前的赋值语句阻断了其后的语句,也就是说后面的语句必须等到当前的赋值语句执行完毕才能执行。而且阻塞赋值可以看成是一步完成的,即:计算等号右边的值并同时赋给左边变量。

    非阻塞赋值,操作符为"<=","非阻塞"是指在进程语句(initial和always)中,当前的赋值语句不会阻断其后的语句。

实验步骤:

    为了详细说明阻塞赋值与非阻塞赋值对实际形成电路的影响,以下写了五个设计。其中端口列表均为以下所示,各部分代码不再重复。

module block_nonblock(Clk,Rst_n,a,b,c,out);

input Clk;

input Rst_n;

input a,b,c;

output
reg
[1:0]out;

。。。。。。。。。。。。。。。

endmodule

 

    首先在时序电路中使用阻塞赋值的方式,生成一个加法器。这种方式生成的实际逻辑电路如图7-1所示。

reg
[1:0] d;

always@(posedge Clk or
negedge Rst_n)

if(!Rst_n)

out =
2'b0;

else
begin

d = a + b ;

out = d + c;

end

 

图7-1

    现在把阻塞赋值的两条语句顺序颠倒一下,再次综合可以得到图7-2所示的逻辑电路。可以在调整顺序后与不调整时生成的逻辑电路不一致。现结合实验原理部分给出详细解释,当执行out = d + c时,d的数据此时并不是更新后a+b的数据,而是上一个Clk上升沿到来时d的数据,这也就解释了为何还有一个D触发器的存在。通俗讲阻塞,out的这条语句阻塞了d的语句执行。对比图7-1的代码,由于d的语句在out的前面,虽然使用了阻塞赋值但是相当于out=a+b+c。

reg
[1:0] d;

always@(posedge Clk or
negedge Rst_n)

if(!Rst_n)

out =
2'b0;

else
begin

out = d + c;

d = a + b;

end

 

图7-2

    现在把赋值方式改为非阻塞赋值,进行综合后可以看到如图7-3所示的逻辑电路。

reg
[1:0] d;

always@(posedge Clk or
negedge Rst_n)

if(!Rst_n)

out <=
2'b0;

else
begin

d <= a + b;

out <= d + c;

end

 

图7-3

    现在使用非阻塞方式,交换语句执行顺序,综合后实现的逻辑电路如图7-4所示。这里由于采用的非阻塞赋值,因此交换语句前后顺序并不会对最终生成的逻辑电路有实际影响。

reg
[1:0] d;

always@(posedge Clk or
negedge Rst_n)

if(!Rst_n)

out <=
2'b0;

else
begin

out <= d + c;

d <= a + b;

end

 

图7-4

 

为了在其各自的时序图中更直观的观察效果,新建仿真block_nonblock_tb.v文件保存到testbench文件夹下,输入以下内容再次进行分析和综合直至没有错误以及警告。本激励文件除产生正常的时钟以及复位信号外,还生成了a、b、c三个信号。这里调用待仿真文件使用的调用方式是显式调用,这种方式要求调用时信号顺序需要与编写的文件顺序一致且不能在一个激励文件中调用两次。可以看出这种方式容易出错,且具有局限性,不推荐使用因此之后的例子均不采用,此处只做介绍。

`timescale
1ns/1ns

`define clock_period 20

 

module block_nonblock_tb;

 

reg Clock;

reg Rst_n;

reg a,b,c;

 

wire
[1:0]out;

 

block_nonblock block_nonblock0(Clock,Rst_n,a,b,c,out);

 

initial Clock =
1;

always#(`clock_period/2) Clock =
~Clock;

 

initial
begin

Rst_n =
1'b0;

a =
0;

b =
0;

c =
0;

#(`clock_period*200
+
1);

Rst_n =
1'b1;

#(`clock_period*200);

a =
0
; b =
0
; c =
0;

#(`clock_period*200);

a =
0
; b =
0
; c =
1;

#(`clock_period*200);

a =
0
; b =
1
; c =
0;

#(`clock_period*200);

a =
0
; b =
1
; c =
1;

#(`clock_period*200);

a =
1
; b =
0
; c =
0;

#(`clock_period*200);

a =
1
; b =
0
; c =
1;

#(`clock_period*200);

a =
1
; b =
1
; c =
0;

#(`clock_period*200);

a =
1
; b =
1
; c =
1;

#(`clock_period*200);

#(`clock_period*200);

$stop;

end

 

endmodule

 

设置好仿真脚本后进行功能仿真,可以看到如图7-5所示的波形文件,可以看出在复位信号置高之前输出为0。直观看上去没有问题。现在放大细节可以看出如图

图7-5

变化在第一个时钟沿之后因此第一个时钟沿检测不到,下一个时钟检测到011 直接赋值计算。

图7-6

    放大细节可以看出,在第一个上升沿out还是0,这是由于虽然是非阻塞赋值并且d已经更新为1,但是实际电路中总会存在延迟,这个时钟沿out已经采不到当前d数据了还是采到0。为了更好的说明进行门级仿真。

图7-7

    全编译后进行门级后仿,可以在图7-8清晰的看出这种现象。

 

 

图7-8

    再次改为非阻塞赋值,如下所示综合出来如图7-9所示。可以与图7-1比较分析。

always@(posedge Clk or
negedge Rst_n)

if(!Rst_n)

out <=
2'b0;

else
begin

out <= a + b + c;

end

 

图7-9

本节对比了 Verilog 语法中阻塞赋值和非阻塞赋值的区别,通过证明非阻塞赋值多种赋值顺序生产电路的唯一性,与非阻塞赋值多种赋值书序生成电路的不确定性,来展示使用非阻塞赋值对设计可预测性的重要意义

掌握可综合风格的Verilog模块编程的八个原则会有很大的帮助。在编写时牢记这八个要点可以为绝大多数的Verilog用户解决在综合后仿真中出现的90-100% 的冒险竞争问题。

1) 时序电路建模时,用非阻塞赋值。

2) 锁存器电路建模时,用非阻塞赋值。

3) 用always块建立组合逻辑模型时,用阻塞赋值。

4) 在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值。

5) 在同一个always块中不要既用非阻塞赋值又用阻塞赋值。

6) 不要在一个以上的always块中为同一个变量赋值。

7) 用$strobe系统任务来显示用非阻塞赋值的变量值

8) 在赋值时不要使用 #0 延迟

07-阻塞赋值与非阻塞赋值原理分析——小梅哥FPGA设计思想与验证方法视频教程配套文档的更多相关文章

  1. 阻塞赋值与非阻塞赋值(verilog篇)

    阻塞赋值与非阻塞赋值(verilog篇) 2017-09-30 竹海 相约电子ee 相信刚刚接触verilog的读者,多少对阻塞赋值和非阻塞赋值仍有一些困惑.笔者在这篇文章,带领大家深入的理解这两者的 ...

  2. FPGA之阻塞赋值与非阻塞赋值

    Verilog语言中讲的阻塞赋值与非阻塞赋值,但从字面意思来看,阻塞就是执行的时候在某个地方卡住了,等这个操作执行完在继续执行下面的语句,而非阻塞就是不管执行完没有,我不管执行的结果是什么,反正我继续 ...

  3. 理论铺垫:阻塞IO、非阻塞IO、IO多路复用/事件驱动IO(单线程高并发原理)、异步IO

    完全来自:http://www.cnblogs.com/alex3714/articles/5876749.html 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同 ...

  4. Java基础知识强化之多线程笔记07:同步、异步、阻塞式、非阻塞式 的联系与区别

    1. 同步: 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回.但是一旦调用返回,就必须先得到返回值了. 换句话话说,调用者主动等待这个"调用"的结果. 对于 ...

  5. Verilog HDL中阻塞语句和非阻塞语句的区别

    在Verilog中有两种类型的赋值语句:阻塞赋值语句(“=”)和非阻塞赋值语句(“<=”).正确地使用这两种赋值语句对于Verilog的设计和仿真非常重要. Verilog语言中讲的阻塞赋值与非 ...

  6. 阻塞IO、非阻塞IO、同步IO、异步IO等

    https://www.cnblogs.com/zingp/p/6863170.html 阅读目录 1 基础知识回顾 2 I/O模式 3 事件驱动编程模型 4 select/poll/epoll的区别 ...

  7. 事件驱动模型 IO多路复用 阻塞IO与非阻塞IO select epool

    一.事件驱动 1.要理解事件驱动和程序,就需要与非事件驱动的程序进行比较.实际上,现代的程序大多是事件驱动的,比如多线程的程序,肯定是事件驱动的.早期则存在许多非事件驱动的程序,这样的程序,在需要等待 ...

  8. 阻塞IO、非阻塞IO的区别

    1.类与类之间的关系:依赖,实现,泛化(继承),关联,组合,聚合. 1)依赖(虚线):一个类是 另一个类的函数参数 或者 函数返回值. 2)实现(实线加小圆):对纯虚函数类(抽象类)的实现. 3)继承 ...

  9. NIO之阻塞IO与非阻塞IO(包含Selector使用)

    阻塞IO 传统的 IO 流都是阻塞式的. 也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务. 因此,在完成网络通信 ...

随机推荐

  1. jxl读取Excel表格数据

    调用jxl包实现Excel表格数据的读取,代码如下: import java.io.File; import java.io.IOException; import java.util.ArrayLi ...

  2. Unity5和WebGL移植指南的一些总结

    对于手游开发者来说,更新版本往往意味着非常复杂的过程,你需要根据反馈做更新.测试.提交然后等待审核,而由于不需要客户端依赖,页游往往是快速测试游戏版本的最佳途径,很多人可能都知道Unity 5可以再不 ...

  3. Tomcat常见问题汇总

    1.在服务器上一定要开启-server参数 #直接在一堆注释下添加即可 #即是在 # OS specific support.注释之前 JAVA_OPTS= -server 2.tomcat启动很慢  ...

  4. 带你玩转JavaWeb开发之六-mysql基本语法详解及实例(1)

    1.1.1    对数据库的表进行操作 1.1.1.1   对数据库中表进行创建 [语法:] create table 表名( 列名 列类型 [列约束], 列名 列类型 [列约束], 列名 列类型 [ ...

  5. Python学习【第五篇】循环语句

    Python循环语句 接下来将介绍Python的循环语句,程序在一般情况下是按顺序执行的. 编程语言提供了各种控制结构,允许更复杂的执行路径. 循环语句允许我们执行一个语句或语句组多次. Python ...

  6. 16C554(8250)驱动分析

    参考: http://www.cnblogs.com/zym0805/p/4815041.html 一. 硬件数据手册 The ST16C554D is a universal asynchronou ...

  7. jNotify:操作结果信息提示条

    我们在提交表单后,通过Ajax响应后台返回结果,并在前台显示返回信息,jNotify能非常优雅的显示操作结果信息.jNotify是一款基于jQuery的信息提示插件,它支持操作成功.操作失败和操作提醒 ...

  8. Mysql查看版本,端口命令

    有一段时间没有鼓捣TP了,今天又再复习一下.在Model获取数据的时候提示'MySQL server has gone away'错误,一开始以为是TP问题,还查了半天,后来才发现是配置mysql的时 ...

  9. storage disk

    scsi fdisk -l can not display the new disk Rescan the SCSI Bus to Add a SCSI Device Without rebootin ...

  10. Response.End抛出ThreadAbortException 异常

    最近在写程序过程中遇到了一个匪夷所思的错误:Response.End()方法抛出了ThreadAbortException异常,我的代码如下: public void doResponse(){ st ...