我是靠谱客的博主 大气心情,最近开发中收集的这篇文章主要介绍阻塞(=)赋值和非阻塞(<=)赋值,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述



在写组合逻辑电路的代码时,我发现书上例子大都用的"=";而在写时序逻辑电路代码时,我发现书上例子大都用的"<="。之前就知道在Verilog HDL中阻塞赋值"="非阻塞赋值"<="有着很大的不同,但一直没有搞清楚究竟有什么不同,现在来慢慢的琢磨它。

  对于我这样的初学者而言,首先要掌握可综合风格的Verilog模块编程的8个原则,并且牢记,才能在综合布局布线的仿真中避免出现竞争冒险现象。

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

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

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

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

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

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

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

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

  这样做的目的是为了使综合前仿真综合后仿真一致。在很多时候,用"="或者是"<="实际上对应的是不同的硬件电路,这点一定要十分清楚。

 


关键是组合逻辑中是实时变化的,而时序逻辑中一个cycle才变化一次
比如:
always @(a or b)
begin
c = a + b;
end
always @(posedge clk)
begin
if(rst)
c <= 0;
else
c <= a + b;
end
在组合逻辑的always block中,a和b的变化都会引起c值的变化;
而时序逻辑中c至少会维持一个clock cycle,也就是说如果a和b的变化导致c变化的时间是在下一个clock的上升沿,而不会让c立刻改变
--------------------------------------------------------------------------------------------------------------------
好,说正题
阻塞赋值“=”与非阻塞赋值“<=”的本质区别在于:
非阻塞赋值语句右端表达式计算完后并不立即赋值给左端,而是同时启动下一条语句继续执行,可以将其理解为所有的右端表达式RHS1、RHS2等在进程开始时同时计算,计算完后 ,等进程结束时同时分别赋给左端变量LHS1、LHS2等;
而阻塞赋值语句在每个右端表达式计算完后立即赋给左端变量,即赋值语句LHS1=RHS1执行完后LHS1是立即更新的,同时只有LHS1=RHS1执行完后才可执行语句LHS1=RHS2,依次类推。前一条语句的执行结果直接影响到后面语句的执行结果。


  阻塞赋值(=):

  我们先做下面定义:RHS—赋值等号右边的表达式,LHS—赋值等号左边的表达式。在串行语句块中,阻塞赋值语句按照它们在块中的排列顺序依次执行,即前一条语句没有完成赋值之前,后面的语句不可能被执行,换言之,后面的语句被阻塞了。阻塞赋值的执行可以认为只有一个步骤的操作,即计算RHS并更新LHS,此时不允许有来自任何其他Verilog语句的干扰。所谓阻塞的概念是指在同一个always块中,其后面的赋值语句从概念上是在前一条赋值语句结束后开始赋值的。有句话我一直没读懂:从理论上讲,它与后面的赋值语句只有概念上的先后,而无实质上的延时。

  例如:

  begin

    B = A;

    C = B + 1;

  end

  首先第一条语句执行,将A的值赋给B,接着执行第二条语句,将B+1(即A加1),并赋给C。也就是说C = A + 1。

 

  非阻塞赋值(<=):

  非阻塞语句的执行过程是:首先计算语句块内部所有右边表达式(RHS)的值,然后完成对左边寄存器变量的赋值操作,例如,下面两条非阻塞赋值语句的执行过程是:先计算右边表达式的值并暂存在一个暂存器中,A的值被保存在一个寄存器中,而B+1的值被保存在另一个寄存器中,在begin和end之间所有语句的右边表达式都被计算并存储完后,对左边的寄存器变量的赋值才会进行。这样C得到的是B的原始值而不是A加一。

  begin

    B <= A;

    C <= B +1;

  end

 

  如果我们想让两个最基本的D触发器串联,我们用阻塞和非阻塞赋值看看结果有什么不同

  阻塞和非阻塞的不同造成了电路上巨大的不同,因此他们的差别应该牢记。

  我们在从仿真(Simulation)的角度去看一下,在输出结果上有造成什么样的不同,我们有同样的的testbench。

 

代码
1 `timescale 1 ps / 1 ps
2   module blocking_vlg_tst();
3
4   reg clk;
5   reg iD;
6 // wires
7 wire oQA;
8 wire oQB;
9
10 // assign statements (if any)
11 blocking i1 (
12 // port map - connection between master ports and signals/registers
13 .clk(clk),
14 .iD(iD),
15 .oQA(oQA),
16 .oQB(oQB)
17 );
18 initial
19 begin
20 clk = 1 ' b0;
21 iD = 1 ' b0;
22 end
23
24 always # 10 clk = ( ~ clk);
25
26 always
27 begin
28 # 8 iD = ( ~ iD);
29 end
30 endmodule
31

 

  仿真波形如下:

  可以看到,在阻塞赋值的情况下当时钟上升沿来的时候读取输入iD的值,并且输出oQA和oQB的值应该是一样的,从波形中我们可以看出输出oQA和oQB的波形是完全一样的。

  在非阻塞赋值的情况下,它是先计算 iD 和 oQA的值,开始 iD的值为1, oQA的值是不定的,所以oQA被赋为1, 而oQB还是被赋为不定值,两者的波形不一致。

 

  阻塞和非阻塞的学习随着以后的深入还得深刻理解,在用时要遵循规则,避免麻烦。








原文地址:http://www.eefocus.com/weidk/blog/2012-04/214655_54407.html

最后

以上就是大气心情为你收集整理的阻塞(=)赋值和非阻塞(<=)赋值的全部内容,希望文章能够帮你解决阻塞(=)赋值和非阻塞(<=)赋值所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部