深入理解阻塞和非阻塞赋值.ppt

上传人:sccc 文档编号:5392658 上传时间:2023-07-02 格式:PPT 页数:70 大小:654.01KB
返回 下载 相关 举报
深入理解阻塞和非阻塞赋值.ppt_第1页
第1页 / 共70页
深入理解阻塞和非阻塞赋值.ppt_第2页
第2页 / 共70页
深入理解阻塞和非阻塞赋值.ppt_第3页
第3页 / 共70页
深入理解阻塞和非阻塞赋值.ppt_第4页
第4页 / 共70页
深入理解阻塞和非阻塞赋值.ppt_第5页
第5页 / 共70页
点击查看更多>>
资源描述

《深入理解阻塞和非阻塞赋值.ppt》由会员分享,可在线阅读,更多相关《深入理解阻塞和非阻塞赋值.ppt(70页珍藏版)》请在三一办公上搜索。

1、深入理解阻塞和非阻塞赋值的不同,概述,1、阻塞赋值对应的电路往往与触发沿没有关系,只与输入电平的变化有关系。阻塞赋值符号:=2 非阻塞赋值对应的电路结构往往与触发沿有关系,只有在触发沿时才有可能发生赋值的情况。非阻塞赋值符号:=,阻塞赋值和非阻塞赋值,阻塞(Blocking)赋值方式“=”,如 b=a;赋值语句执行完后,块才结束。b的值在赋值语句执行完后立刻就改变的。非阻塞(Non_Blocking)赋值方式“”,如 b=a;块结束后才完成赋值操作。b的值并不是立刻就改变的。这是一种比较常用的赋值方法(特别在编写可综合时序模块时)。,阻塞赋值,阻塞赋值操作符用等号(即=)表示。阻塞赋值时先计算

2、等号右手方向(RHS)部分的值,这时赋值语句不允许任何别的语句的干扰,直到现行的赋值完成时刻,即把RHS赋值给 LHS的时刻,它才允许别的赋值语句的执行。一般可综合的阻塞赋值操作在RHS不能设定有延迟,(即使是零延迟也不允许)。若在RHS 加上延迟,则在延迟期间会阻止赋值语句的执行,延迟后才执行赋值,这种赋值语句是不可综合的,在需要综合的模块设计中不可使用这种风格的代码。阻塞赋值的执行可以认为是只有一个步骤的操作:所谓阻塞的概念是指在同一个always块中,其后面的赋值语句从概念上(即使不设定延迟)是在前一句赋值语句结束后再开始赋值的。,非阻塞赋值,非阻塞赋值操作符用小于等于号(即=)表示。在

3、赋值操作时刻开始时计算非阻塞赋值符的RHS表达式,赋值操作时刻结束时更新LHS。在计算非阻塞赋值的RHS表达式和更新LHS期间,其他的Verilog语句,包括其他的Verilog非阻塞赋值语句都能同时计算RHS表达式和更新LHS。非阻塞赋值允许其他的Verilog语句同时进行操作。非阻塞赋值的操作可以看作为两个步骤的过程:1)在赋值时刻开始时,计算非阻塞赋值RHS表达式。2)在赋值时刻结束时,更新非阻塞赋值LHS表达式。非阻塞赋值操作只能用于对寄存器类型变量进行赋值,因此只能用在“initial”块和“always”块等过程块中。非阻塞赋值不允许用于连续赋值。,难点,1 何时使用非阻塞赋值,何

4、时使用阻塞赋值才能设计出符合要求的电路。2 在可综合风格的Verilog模块的设计中,为什么还要用非阻塞赋值,以及符合IEEE 标准的Verilog 仿真器究竟如何来处理非阻塞赋值的仿真。本小节明确地提出可综合的Verilog模块编程在使用赋值操作时应注意的要点,按照这些要点来编写代码就可以避免在Verilog 仿真时出现冒险和竞争的现象,非阻塞赋初值导致错误,阻塞赋初值正确,综合后波形对比,仿真波形对比,要 点,1 在描述组合逻辑的always块中用阻塞赋值,则综合成组合逻辑的电路结构。2 在描述时序逻辑的always块中用非阻塞赋值,则综合成时序逻辑的电路结构。RHS 方程式右手方向的表达

5、式或变量可分别缩写为:RHS表达式或RHS变量。LHS 方程式左手方向的表达式或变量可分别缩写为:LHS表达式或LHS变量。,深入理解阻塞的概念,阻塞赋值的执行可以认为是只有一个步骤的操作:计算RHS并更新LHS,此时不能允许有来自任何其他Verilog语句的干扰。所谓阻塞的概念是指在同一个always块中,其后面的赋值语句从概念上(即使不设定延迟)是在前一句赋值语句结束后再开始赋值的。如果在一个过程块中阻塞赋值的RHS变量正好是另一个过程块中阻塞赋值的LHS变量,这两个过程块又用同一个时钟沿触发,这时阻塞赋值操作会出现问题,即如果阻塞赋值的次序安排不好,就会出现竞争。若这两个阻塞赋值操作用同

6、一个时钟沿触发,则执行的次序是无法确定的。,深入理解非阻塞的概念,非阻塞赋值的操作可以看作为两个步骤的过程:1 在赋值时刻开始时,计算非阻塞赋值RHS表达式。2 在赋值时刻结束时,更新非阻塞赋值LHS表达式。非阻塞赋值操作只能用于对寄存器类型变量进行赋值,因此只能用在“initial”块和“always”块等过程块中。非阻塞赋值不允许用于连续赋值。,阻塞赋值,非阻塞赋值,阻塞赋值,wire dinreg a,b,c;always(posedge ck)begin a=din;b=a;c=b;end,非阻塞赋值,wire dinreg a,b,c;always(posedge ck)begin

7、a=din;b=a;c=b;end,wire dinreg a,b,c;always(posedge ck)begin a=din;b=a;c=b;end,阻塞赋值,非阻塞赋值,wire dinreg a,b,c;always(posedge ck)begin a=din;b=a;c=b;end,D,CK,Q,DIN,CK,C,C=DIN;,CK,C,A,B,Verilog模块编程要点,1 时序电路建模时,用非阻塞赋值。2 锁存器电路建模时,用非阻塞赋值。3 用always块建立组合逻辑模型时,用阻塞赋值。4 在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值。5 在同一个alwa

8、ys块中不要既用非阻塞赋值又用阻塞赋值。6 不要在一个以上的always块中为同一个变量赋值。7 用$strobe系统任务来显示用非阻塞赋值的变量值8 在赋值时不要使用#0 延迟,Verilog 的层次化事件队列,说明,事件是按照一定的规则被加入到5 个区域中任意一个区域的,但是只从其中的“活跃事件”区域出队,出队之后该事件将会立刻执行。仿真器首先按照仿真时间对事件进行排序,然后再在当前仿真时间里按照事件的优先级顺序进行排序。活跃事件是优先级最高的事件。在活跃事件之间,它们的执行顺序是随机的。阻塞赋值(=)、连续赋值Cassign)以及非阻塞赋值的右式计算等都属于活跃事件。将来仿真时间里的所有

9、事件都将暂时存放在将来事件队列中。当仿真器前进到某个时刻后,该时刻的所有事件也会被分类到当前仿真时间事件队列中,而仿真时刻未到的事件则仍然留在将来事件队列中。,自触发always块,例3 使用阻塞赋值的非自触发振荡器 module osc1(clk);output clk;reg clk;initial#10 clk=0;always(clk)#10 clk=clk;endmodule,例4 采用非阻塞赋值的自触发振荡器,module osc2(clk);output clk;reg clk;initial#10 clk=0;always(clk)#10 clk=clk;Endmodule,移

10、位寄存器模型,下图表示是一个简单的移位寄存器方框图。,例5 不正确地使用的阻塞赋值来描述移位寄存器。(方式#1),module pipeb1(q3,d,clk);output 7:0 q3;input 7:0 d;input clk;reg 7:0 q3,q2,q1;always(posedge clk)begin q1=d;q2=q1;q3=q2;end endmodule,D的值赋给Q1以后,再执行Q2=Q1;同样在Q2的值更新以后,才执行Q3=Q2。这样,最终的计算结果就是Q3=D。即在每一个clk边沿,输入值被无延迟地传到q3的输出。这很明显并没有建立一个流水线而只是为一个寄存器建模-

11、,例6 用阻塞赋值来描述移位寄存器也是可行的,但这种风格并不好。(方式#2)module pipeb2(q3,d,clk);output 7:0 q3;input 7:0 d;input clk;reg 7:0 q3,q2,q1;always(posedge clk)begin q3=q2;q2=q1;q1=d;end endmodule阻塞赋值被仔细地安排了次序以使得行为仿真正确。这种建模同样也可以得到正确的综合结果,例7 不好的用阻塞赋值来描述移位时序逻辑的风格(方式#3)module pipeb3(q3,d,clk);output 7:0 q3;input 7:0 d;input clk

12、;reg 7:0 q3,q2,q1;always(posedge clk)q1=d;always(posedge clk)q2=q1;always(posedge clk)q3=q2;endmodule,阻塞赋值”被安排在不同的always块里面。这样Verilog标准允许以任意的次序来仿真执行3个always块-这也许会使得该流水线仿真结果产生错误,因为这产生了Verilog竞争条件。由不同的always块执行顺序会产生不同的结果。尽管这样,它的综合结果将是正确的!这就意味着综合前仿真和综合后仿真不匹配,例8 不好的用阻塞赋值来描述移位时序逻辑的风格(方式#4)module pipeb4(q

13、3,d,clk);output 7:0 q3;input 7:0 d;input clk;reg 7:0 q3,q2,q1;always(posedge clk)q2=q1;always(posedge clk)q3=q2;always(posedge clk)q1=d;endmodule,颠倒了一下赋值次序,对实际仿真次序却不产生决定作用,综合结果是对的,但是仿真结果也许不正确,例9 正确的用非阻塞赋值来描述时序逻辑的设计风格#1 module pipen1(q3,d,clk);output 7:0 q3;input 7:0 d;input clk;reg 7:0 q3,q2,q1;alwa

14、ys(posedge clk)begin q1=d;q2=q1;q3=q2;end endmodule,注意,*仿真器首先按照仿真时间对事件进行排序,然后再在当前仿真时间里按照事件的优先级顺序进行排序。*活跃事件是优先级最高的事件。在活跃事件之间,它们的执行顺序是随机的。阻塞赋值(=)、连续赋值(assign)以及非阻塞赋值的右式计算等都属于活跃事件。,例10 正确的用非阻塞赋值来描述时序逻辑的设计风格#2 module pipen2(q3,d,clk);output 7:0 q3;input 7:0 d;input clk;reg 7:0 q3,q2,q1;always(posedge cl

15、k)begin q3=q2;q2=q1;q1=d;end endmodule,例11 正确的用非阻塞赋值来描述时序逻辑的设计风格#3 module pipen3(q3,d,clk);output 7:0 q3;input 7:0 d;input clk;reg 7:0 q3,q2,q1;always(posedge clk)q1=d;always(posedge clk)q2=q1;always(posedge clk)q3=q2;endmodule,例12 正确的用非阻塞赋值来描述时序逻辑的设计风格#4module pipen4(q3,d,clk);output 7:0 q3;input 7

16、:0 d;input clk;reg 7:0 q3,q2,q1;always(posedge clk)q2=q1;always(posedge clk)q3=q2;always(posedge clk)q1=d;endmodule,例题总结,四种阻塞赋值设计方式中有一种可以保证仿真正确四种阻塞赋值设计方式中有三种可以保证综合正确四种非阻塞赋值设计方式全部可以保证仿真正确四种非阻塞赋值设计方式全部可以保证综合正确 虽然在一个always块中正确的安排赋值顺序,用阻塞赋值也可以实现移位寄存器时序流水线逻辑。但是,用非阻塞赋值实现同一时序逻辑要相对简单,而且,非阻塞赋值可以保证仿真和综合的结果都是一

17、致和正确的。因此建议大家在编写Verilog时序逻辑时要用非阻塞赋值的方式。,时序反馈移位寄存器建模,线性反馈移位寄存器(Linear Feedback Shift-Register 简称LFSR)是带反馈回路的时序逻辑。,module lfsrb1(q3,clk,pre_n);output q3;input clk,pre_n;reg q3,q2,q1;wire n1;assign n1=q1 q3;always(posedge clk or negedge pre_n)if(!pre_n)begin q3=1b1;q2=1b1;q1=1b1;end,else begin q3=q2;q2=

18、n1;q1=q3;end endmodule,线性反馈移位寄存器,RTL级电路,思考:真正的LFSR电路图是什么样子?,用阻塞赋值描述的线性反馈移位寄存器,其功能正确,但模型的含义较难理解。module lfsrb2(q3,clk,pre_n);output q3;input clk,pre_n;reg q3,q2,q1;always(posedge clk or negedge pre_n)if(!pre_n)q3,q2,q1=3b111;else q3,q2,q1=q2,(q1q3),q3;endmodule 把所有赋值弄到一个等式的方式(one-line equations)来避免使用临

19、时变量编码显得更难于理解尤其当涉及的表达式更大更长时,编写代码和调试都变得比较困难,因此不鼓励使用这种风格,用非阻塞语句描述的LFSR,可综合,其功能正确。,module lfsrb1(q3,clk,pre_n);output q3;input clk,pre_n;reg q3,q2,q1;wire n1;assign n1=q1 q3;always(posedge clk or negedge pre_n)if(!pre_n)begin q3=1b1;q2=1b1;q1=1b1;end,else begin q3=q2;q2=n1;q1=q3;endendmodule,RTL级电路,例 用非

20、阻塞语句描述的LFSR,可综合其功能正确。module lfsrn2(q3,clk,pre_n);output q3;input clk,pre_n;reg q3,q2,q1;always(posedge clk or negedge pre_n)if(!pre_n)q3,q2,q1=3b111;else q3,q2,q1=q2,(q1q3),q3;endmodule,移位寄存器设计,1 含同步预置功能的移位寄存器设计REG86:0=REG87:1;,工作时序图,模式可控的移位寄存器设计,2 使用移位操作符设计移位寄存器,移位寄存器的RTL图,阻塞赋值及一些简单的例子,例13 module d

21、ffb(q,d,clk,rst);output q;input d,clk,rst;reg q;always(posedge clk)if(rst)q=1b0;else q=d;endmodule,虽然可行也很简单,但我们不建议这种用阻塞赋值来描述D触发器模型的风格。如果要把所有的模块写到一个always块里,是可以采用阻塞赋值得到正确的建模、仿真并综合成期望的逻辑。但是,这种想法将导致使用阻塞赋值的习惯,而在较为复杂的多个always块的情况下可能会导致竞争冒险,例14 使用非阻塞赋值来描述D触发器是建议使用的风格 module dffx(q,d,clk,rst);output q;inpu

22、t d,clk,rst;reg q;always(posedge clk)if(rst)q=1b0;else q=d;endmodule,小结,从上面介绍的移位寄存器的例子以及LFSR的例子,建议使用非阻塞赋值实现时序逻辑。而用非阻塞赋值语句实现锁存器也是最为安全的。原则1:时序电路建模时,用非阻塞赋值。原则2:锁存器电路建模时,用非阻塞赋值。,组合逻辑使用阻塞赋值,用Verilog可以有很多种方法为组合逻辑建模,但是当使用always块来为组合逻辑建模时,应该使用阻塞赋值(blocking assignment)。如果在某个always块里面只有一个赋值(表达),使用阻塞或者非阻塞赋值都可以

23、正确工作。但是如果您对养成好的编码习惯有兴趣的话,还是要“总是用阻塞赋值对组合逻辑建模”。对于简单的组合alwasys块不仅可以用于时序逻辑,也可以用于组合逻辑,但是当always块中有多个赋值语句时使用了不含延迟(delay)的非阻塞赋值会造成仿真不正确,或者要使仿真正确您需要另外的添加敏感事件列表(sensitivity list entries),和“多输入路径”(multiple passes)来贯穿always 块以使得仿真正确。因而从仿真的时间效率角度看也不合算。,例module ao4(y,a,b,c,d);output y;input a,b,c,d;reg y,tmp1,tm

24、p2;always(a or b or c or d)begin tmp1=a end endmodule y输出建立在3个依次执行的顺序上。由于非阻塞赋值的LHS变量值更新是在对RHS表达式估值之后,所以tmp1和tmp2的值仍然是该always块上一个输入口的值而不是在这一个仿真时间步(simulation time step)结束时被更新的值。因此y的值将受旧的tmp1和tmp2影响,而不是这次扫描过的always块内被更新的值。,例 module ao5(y,a,b,c,d);output y;input a,b,c,d;reg y,tmp1,tmp2;5 always(a or b

25、or c or d or tmp1 or tmp2)begin tmp1=a end endmodule,不同之处在于tmp1和tmp2被添加到事件列表中去了,当非阻塞赋值更新LHS变量时,always块将会“自触发”并使用最新的tmp1和tmp2来更新y输出。现在y输出值正确了因为增加使用了两条“登入路径”(two passes)贯穿整个always块。使用更多的“登入路径”来贯穿always块等于降低仿真器的性能,因此如果可以有合理的一些代码变化可以取代这 种用法的话,就尽量避免这种用法。,例 使用阻塞赋值实现组合逻辑是推荐使用的编码风格。module ao2(y,a,b,c,d);out

26、put y;input a,b,c,d;reg y,tmp1,tmp2;always(a or b or c or d)begin tmp1=a end endmodule,小结,原则3:用always块描述组合逻辑时,应采用阻塞赋值语句,时序和组合的混合逻辑使用非阻塞赋值,有时候将简单的组合逻辑和时序逻辑写在一起很方便。当把组合逻辑和时序逻辑写到一个always块中时,应遵从时序逻辑建模的原则,使用非阻塞赋值,如例所示。例2 在一个always块中同时实现组合逻辑和时序逻辑 module nbex2(q,a,b,clk,rst_n);output q;input clk,rst_n;inpu

27、t a,b;reg q;always(posedge clk or negedge rst_n)if(!rst_n)q=1b0;/时序逻辑 else q=a b;/异或,为组合逻辑 endmodule,例 将组合和时序逻辑分别写在两个always块中,一个是纯粹的时序逻辑(使用非阻塞赋值),另一个是纯粹的组合逻辑(使用阻塞赋值)建模 module nbex1(q,a,b,clk,rst_n);output q;input clk,rst_n;input a,b;reg q,y;always(a or b)y=a b;always(posedge clk or negedge rst_n)if(

28、!rst_n)q=1b0;else q=y;endmodule,小结,原则4:在同一个always块中描述时序和组合逻辑混合电路时,用非阻塞赋值。,其它混合“阻塞”与“非阻塞”赋值建模方针,Verilog语法并没有禁止将阻塞和非阻塞赋值自由地组合在一个always块里。虽然Verilog语法是允许这种写法的,但我们不建议在可综合模块的编写中采用这种风格,例24 在always块中同时使用阻塞和非阻塞赋值的例子。module ba_nba2(q,a,b,clk,rst_n);output q;input a,b,rst_n;input clk;reg q;always(posedge clk o

29、r negedge rst_n)begin:ff reg tmp;if(!rst_n)q=1b0;else begin tmp=a end end endmodule,仿真和综合都将是正确的,因为“阻塞”与“非阻塞”赋值不是针对同一个变量来的。尽管这可以“正常工作”,但是不推荐这种风格。,例 对同一变量既进行阻塞赋值,又进行非阻塞赋值有时会产生综合错误。module ba_nba6(q,a,b,clk,rst_n);output q;input a,b,rst_n;input clk;reg q,tmp;always(posedge clk or negedge rst_n)if(!rst_n

30、)q=1b0;/对 q进行阻塞赋值 else begin tmp=a/对 q进行非阻塞赋值 end endmodule,小结,原则5:不要在同一个always块中同时使用阻塞和非阻塞赋值,对同一变量进行多次赋值,在一个以上always块中对同一个变量进行多次赋值可能会导致竞争冒险,即使使用非阻塞赋值也可能产生竞争冒险。在下例中,两个always块都对输出q进行赋值。由于两个always块执行的顺序是随机的,所以仿真时会产生竞争冒险,例25 使用非阻塞赋值语句,由于两个always块对同一变量q赋值产生竞争冒险的程序:module badcode1(q,d1,d2,clk,rst_n);outp

31、ut q;input d1,d2,clk,rst_n;reg q;always(posedge clk or negedge rst_n)if(!rst_n)q=1b0;else q=d1;always(posedge clk or negedge rst_n)if(!rst_n)q=1b0;else q=d2;endmodule,在synplify Pro下综合,产生错误信息:E:Only one always block may assign a given variable q,综合出现的错误,小结,原则6:严禁在多个always块中对同一个变量赋值,常见的对于非阻塞赋值的误解,1 非阻

32、塞赋值和$display误解1:“使用$display命令不能用来显示非阻塞语句的赋值”事实是:非阻塞语句的赋值在所有的$display命令执行以后才更新数值2#0 延时赋值 误解2:“0延时把赋值强制到仿真时间步的末尾”事实是:0延时将赋值事件强制加入停止运行事件队列中。,例module display_cmds;reg a;initial$monitor($monitor:a=%b,a);initial begin$strobe($strobe:a=%b,a);a=0;a=1;$display($display:a=%b,a);#1$finish;end endmodule,下面是上面模块

33、的仿真结果说明$display命令的执行是安排在活动事件队列中,但排在非阻塞赋值数据更新事件之前。$display:a=0$monitor:a=1$strobe:a=1,例28 module nb_schedule1;reg a,b;initial begin a=0;b=1;a=b;b=a;$monitor(%0dns:$monitor:a=%b b=%b,$stime,a,b);$display(%0dns:$display:a=%b b=%b,$stime,a,b);$strobe(%0dns:$strobe:a=%b b=%bn,$stime,a,b);#0$display(%0dns

34、:#0:a=%b b=%b,$stime,a,b);#1$monitor(%0dns:$monitor:a=%b b=%b,$stime,a,b);$display(%0dns:$display:a=%b b=%b,$stime,a,b);$strobe(%0dns:$strobe:a=%b b=%bn,$stime,a,b);$display(%0dns:#0:a=%b b=%b,$stime,a,b);,#1$finish;end endmodule下面是上面模块的仿真结果说明0延时命令在非阻塞赋值事件发生前,在停止运行事件队列中执行。0ns:$display:a=0 b=1 0ns:#0

35、:a=0 b=1 0ns:$monitor:a=1 b=0 0ns:$strobe:a=1 b=0 1ns:$display:a=1 b=0 1ns:#0:a=1 b=0 1ns:$monitor:a=1 b=0 1ns:$strobe:a=1 b=0,小结,原则7:用$strobe系统任务来显示用非阻塞赋值的变量值,对同一变量进行多次非阻塞赋值,误解3:“在Verilog语法标准中未定义可在同一个always块中对某同一变量进行多次非阻塞赋值”。事实是:Verilog标准定义了在同一个always块中可对某同一变量进行多次非阻塞赋值但多次赋值中,只有最后一次赋值对该变量起作用。“非阻塞赋值按

36、照语句的顺序执行,请看下例:initial begin a=0;a=1;end 执行该模块时,有两个非阻塞赋值更新事件加入到非阻塞赋值更新队列。以前的规则要求将非阻塞赋值更新事件按照它们在源文件的顺序加入队列,这便要求按照事件在源文件中的顺序,将事件从队列中取出并执行。因此,在仿真第一步结束的时刻,变量a被设置为0,然后为1。”结论:最后一个非阻塞赋值决定了变量的值。,总结,原则1:时序电路建模时,用非阻塞赋值。原则2:锁存器电路建模时,用非阻塞赋值。原则3:用always块写组合逻辑时,采用阻塞赋值。原则4:在同一个always块中同时建立时序和组合逻辑电路时,用非阻塞赋值。原则5:在同一个always块中不要同时使用非阻塞赋值和阻塞赋值。原则6:不要在多个always块中为同一个变量赋值。原则7:用$strobe系统任务来显示用非阻塞赋值的变量值原则8:在赋值时不要使用#0 延迟,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 建筑/施工/环境 > 农业报告


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号