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

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

?

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

实验平台:无

实验原理:

????阻塞赋值,操作符为"=","阻塞"是指在进程语句(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 延迟

时间: 2024-10-31 16:48:21

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

阻塞赋值与非阻塞赋值(转载)

 前言:阻塞与非阻塞赋值是Verilog语言中最基本的部分,也是让大部分Verilog新手最困惑的地方.关于阻塞与非阻塞的著作文章可谓汗牛充栋,这些文章对阻塞与非阻塞赋值的原理进行了非常详细的讲解,但新手读了之后依然有种似懂非懂的感觉,编码过程中一如既往的犯错.所以,本文的目的立足于提供一种实用化的解决方案,用最简单的语言和形象的类比让新手能够一目了然的明白正确的编码方式以及相应的电路行为逻辑,关于仿真细节的讲解不是本文重点,需要了解更多细节的朋友可以参考文后列举的参考文献. 本文共分为三部分,

阻塞赋值与非阻塞赋值

     过程赋值:用于对reg型变量赋值,改变寄存器的值或为以后排定改变.      语法 {阻塞性(blocking)赋值} RegisterLValue = [ TimingControl] Expression; {非阻塞性(non-blocking)赋值} RegisterLValue <= [ TimingControl] Expression; 阻塞:在本语句中"右式计算"和"左式更新"完全完成之后,才开始执行下一条语句: 非阻塞:当前语句的执行

Verilog阻塞赋值与非阻塞赋值

今天又个兄弟求助,数据库里一个表有数据如下: no  name 1    a 2    b 3    c 4    d 如何用一个sql显示如下结果: ab ac ad bc bd cd 对于这种构造数据,是分析函数的强项,下面来做个试验: create table t (no number,name varchar(2)); insert into t values(1,'a'); insert into t values(2,'b'); insert into t values(3,'c')

关于verilog阻塞赋值与非阻塞赋值的一些浅见

最近学到了关于verilog的阻塞赋值与非阻塞赋值的一些区别,经过网上查阅与仿真实验,有了一些理解.希望能够记下来. 说到verilog的阻塞与非阻塞赋值,不得不说的就是verilog的事件表,如下: 阻塞赋值,属于活跃事件,计算完RHS(Right Hand Side)立即更新左值.期间同一块内其他语句不能执行,即阻塞其他语句执行. 而非阻塞右值计算属于活跃事件,非阻塞左值更新属于非活跃事件,即计算完RHS,不能立即更新左值,而要等所有活跃事件完成,才能完成左值更新,出事件队列.   然后说说

用一个例子来学习阻塞赋值和非阻塞赋值

阻塞赋值与非阻塞赋值 阻塞赋值的一般表达式为:目标变量名=驱动表达式  阻塞赋值是一种理想化的数据传输,赋值立即发生,不存在延时行为 非阻塞赋值一般表达式为:目标变量名<=驱动表达式   非阻塞赋值比较接近真实的电路工作状态,应为他从综合的角度考虑到了延时和并行性. 在过程启动中,非阻塞赋值使三条语句同时运行,而阻塞赋值是按顺序方式完成更新的数据的. 新建工程,编写示例代码 module block_nonblock(clk,rst_n,a,b,c,out ); input clk,rst_n,

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

Verilog语言中讲的阻塞赋值与非阻塞赋值,但从字面意思来看,阻塞就是执行的时候在某个地方卡住了,等这个操作执行完在继续执行下面的语句,而非阻塞就是不管执行完没有,我不管执行的结果是什么,反正我继续下面的事情.而Verilog中的阻塞赋值与非阻塞赋值正好也是这个意思,通过执行一个例子,就可以简单地明白了:1.阻塞赋值可以理解为语句的顺序执行,因此语句的执行顺序很重要2.非阻塞赋值可以理解为语句的并行执行,所以语句的执行不考虑顺序3.在assign的结构中,必须使用的是阻塞赋值 //阻塞modu

阻塞赋值和非阻塞赋值

2017-12-01 在Verilog语言中,赋值语句经常使用,阻塞赋值和非阻塞赋值经常带给我们很多困扰.在此讨论两种赋值方式的差异性. 首先根据表面含义深刻理解阻塞和非阻塞: 阻塞:在进程语句块中(initial或者always或者其他),当前赋值语句的执行阻塞了后面语句的执行.即后面语句的赋值需要等到当前赋值过程完成才能得以执行,即可认为执行过程是顺序执行的(我们要明白Verilog中,大多数情况模块都是并发执行的). 非阻塞:当前赋值语句的执行不会阻塞后续语句的执行,即可以认为当前赋值语句

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

1. 同步: 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回.但是一旦调用返回,就必须先得到返回值了. 换句话话说,调用者主动等待这个"调用"的结果. 对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已. 2. 异步: 所谓异步,"调用"在发出之后,这个调用就直接返回了,所以没有返回结果. 换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果.而是在"调用"发出后,"被调用者&q

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

完全来自:http://www.cnblogs.com/alex3714/articles/5876749.html 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network IO. 一 概念说明 在进行解释之前,首先要说明几个概念:- 用户空间和内核空间- 进程切换- 进程的阻塞- 文件描述符- 缓存 I/O 用户空间与内核空间 现在操作系统都是采用虚拟存储器,