深入理解阻塞和非阻塞赋值的不同_第1页
深入理解阻塞和非阻塞赋值的不同_第2页
深入理解阻塞和非阻塞赋值的不同_第3页
深入理解阻塞和非阻塞赋值的不同_第4页
深入理解阻塞和非阻塞赋值的不同_第5页
已阅读5页,还剩65页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

深入理解阻塞和非阻塞赋值的不同,概述,1、阻塞赋值对应的电路往往与触发沿没有关系,只与输入电平的变化有关系。阻塞赋值符号:=2非阻塞赋值对应的电路结构往往与触发沿有关系,只有在触发沿时才有可能发生赋值的情况。非阻塞赋值符号:=,阻塞赋值和非阻塞赋值,阻塞(Blocking)赋值方式“=”,如b=a;赋值语句执行完后,块才结束。b的值在赋值语句执行完后立刻就改变的。非阻塞(Non_Blocking)赋值方式“”,如b=a;块结束后才完成赋值操作。b的值并不是立刻就改变的。这是一种比较常用的赋值方法(特别在编写可综合时序模块时)。,阻塞赋值,阻塞赋值操作符用等号(即=)表示。阻塞赋值时先计算等号右手方向(RHS)部分的值,这时赋值语句不允许任何别的语句的干扰,直到现行的赋值完成时刻,即把RHS赋值给LHS的时刻,它才允许别的赋值语句的执行。一般可综合的阻塞赋值操作在RHS不能设定有延迟,(即使是零延迟也不允许)。若在RHS加上延迟,则在延迟期间会阻止赋值语句的执行,延迟后才执行赋值,这种赋值语句是不可综合的,在需要综合的模块设计中不可使用这种风格的代码。阻塞赋值的执行可以认为是只有一个步骤的操作:所谓阻塞的概念是指在同一个always块中,其后面的赋值语句从概念上(即使不设定延迟)是在前一句赋值语句结束后再开始赋值的。,非阻塞赋值,非阻塞赋值操作符用小于等于号(即=)表示。在赋值操作时刻开始时计算非阻塞赋值符的RHS表达式,赋值操作时刻结束时更新LHS。在计算非阻塞赋值的RHS表达式和更新LHS期间,其他的Verilog语句,包括其他的Verilog非阻塞赋值语句都能同时计算RHS表达式和更新LHS。非阻塞赋值允许其他的Verilog语句同时进行操作。非阻塞赋值的操作可以看作为两个步骤的过程:1)在赋值时刻开始时,计算非阻塞赋值RHS表达式。2)在赋值时刻结束时,更新非阻塞赋值LHS表达式。非阻塞赋值操作只能用于对寄存器类型变量进行赋值,因此只能用在“initial”块和“always”块等过程块中。非阻塞赋值不允许用于连续赋值。,难点,1何时使用非阻塞赋值,何时使用阻塞赋值才能设计出符合要求的电路。2在可综合风格的Verilog模块的设计中,为什么还要用非阻塞赋值,以及符合IEEE标准的Verilog仿真器究竟如何来处理非阻塞赋值的仿真。本小节明确地提出可综合的Verilog模块编程在使用赋值操作时应注意的要点,按照这些要点来编写代码就可以避免在Verilog仿真时出现冒险和竞争的现象,非阻塞赋初值导致错误,阻塞赋初值正确,综合后波形对比,仿真波形对比,要点,1在描述组合逻辑的always块中用阻塞赋值,则综合成组合逻辑的电路结构。2在描述时序逻辑的always块中用非阻塞赋值,则综合成时序逻辑的电路结构。RHS方程式右手方向的表达式或变量可分别缩写为:RHS表达式或RHS变量。LHS方程式左手方向的表达式或变量可分别缩写为:LHS表达式或LHS变量。,深入理解阻塞的概念,阻塞赋值的执行可以认为是只有一个步骤的操作:计算RHS并更新LHS,此时不能允许有来自任何其他Verilog语句的干扰。所谓阻塞的概念是指在同一个always块中,其后面的赋值语句从概念上(即使不设定延迟)是在前一句赋值语句结束后再开始赋值的。如果在一个过程块中阻塞赋值的RHS变量正好是另一个过程块中阻塞赋值的LHS变量,这两个过程块又用同一个时钟沿触发,这时阻塞赋值操作会出现问题,即如果阻塞赋值的次序安排不好,就会出现竞争。若这两个阻塞赋值操作用同一个时钟沿触发,则执行的次序是无法确定的。,深入理解非阻塞的概念,非阻塞赋值的操作可以看作为两个步骤的过程:1在赋值时刻开始时,计算非阻塞赋值RHS表达式。2在赋值时刻结束时,更新非阻塞赋值LHS表达式。非阻塞赋值操作只能用于对寄存器类型变量进行赋值,因此只能用在“initial”块和“always”块等过程块中。非阻塞赋值不允许用于连续赋值。,阻塞赋值,非阻塞赋值,阻塞赋值,wiredinrega,b,c;always(posedgeck)begina=din;b=a;c=b;end,非阻塞赋值,wiredinrega,b,c;always(posedgeck)begina=din;b=a;c=b;end,wiredinrega,b,c;always(posedgeck)begina=din;b=a;c=b;end,阻塞赋值,非阻塞赋值,wiredinrega,b,c;always(posedgeck)begina=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在同一个always块中不要既用非阻塞赋值又用阻塞赋值。6不要在一个以上的always块中为同一个变量赋值。7用$strobe系统任务来显示用非阻塞赋值的变量值8在赋值时不要使用#0延迟,Verilog的层次化事件队列,说明,事件是按照一定的规则被加入到5个区域中任意一个区域的,但是只从其中的“活跃事件”区域出队,出队之后该事件将会立刻执行。仿真器首先按照仿真时间对事件进行排序,然后再在当前仿真时间里按照事件的优先级顺序进行排序。活跃事件是优先级最高的事件。在活跃事件之间,它们的执行顺序是随机的。阻塞赋值(=)、连续赋值Cassign)以及非阻塞赋值的右式计算等都属于活跃事件。将来仿真时间里的所有事件都将暂时存放在将来事件队列中。当仿真器前进到某个时刻后,该时刻的所有事件也会被分类到当前仿真时间事件队列中,而仿真时刻未到的事件则仍然留在将来事件队列中。,自触发always块,例3使用阻塞赋值的非自触发振荡器moduleosc1(clk);outputclk;regclk;initial#10clk=0;always(clk)#10clk=clk;endmodule,例4采用非阻塞赋值的自触发振荡器,moduleosc2(clk);outputclk;regclk;initial#10clk=0;always(clk)#10clk=clk;Endmodule,移位寄存器模型,下图表示是一个简单的移位寄存器方框图。,例5不正确地使用的阻塞赋值来描述移位寄存器。(方式#1),modulepipeb1(q3,d,clk);output7:0q3;input7:0d;inputclk;reg7:0q3,q2,q1;always(posedgeclk)beginq1=d;q2=q1;q3=q2;endendmodule,D的值赋给Q1以后,再执行Q2=Q1;同样在Q2的值更新以后,才执行Q3=Q2。这样,最终的计算结果就是Q3=D。即在每一个clk边沿,输入值被无延迟地传到q3的输出。这很明显并没有建立一个流水线而只是为一个寄存器建模-,例6用阻塞赋值来描述移位寄存器也是可行的,但这种风格并不好。(方式#2)modulepipeb2(q3,d,clk);output7:0q3;input7:0d;inputclk;reg7:0q3,q2,q1;always(posedgeclk)beginq3=q2;q2=q1;q1=d;endendmodule阻塞赋值被仔细地安排了次序以使得行为仿真正确。这种建模同样也可以得到正确的综合结果,例7不好的用阻塞赋值来描述移位时序逻辑的风格(方式#3)modulepipeb3(q3,d,clk);output7:0q3;input7:0d;inputclk;reg7:0q3,q2,q1;always(posedgeclk)q1=d;always(posedgeclk)q2=q1;always(posedgeclk)q3=q2;endmodule,阻塞赋值”被安排在不同的always块里面。这样Verilog标准允许以任意的次序来仿真执行3个always块-这也许会使得该流水线仿真结果产生错误,因为这产生了Verilog竞争条件。由不同的always块执行顺序会产生不同的结果。尽管这样,它的综合结果将是正确的!这就意味着综合前仿真和综合后仿真不匹配,例8不好的用阻塞赋值来描述移位时序逻辑的风格(方式#4)modulepipeb4(q3,d,clk);output7:0q3;input7:0d;inputclk;reg7:0q3,q2,q1;always(posedgeclk)q2=q1;always(posedgeclk)q3=q2;always(posedgeclk)q1=d;endmodule,颠倒了一下赋值次序,对实际仿真次序却不产生决定作用,综合结果是对的,但是仿真结果也许不正确,例9正确的用非阻塞赋值来描述时序逻辑的设计风格#1modulepipen1(q3,d,clk);output7:0q3;input7:0d;inputclk;reg7:0q3,q2,q1;always(posedgeclk)beginq1=d;q2=q1;q3=q2;endendmodule,注意,*仿真器首先按照仿真时间对事件进行排序,然后再在当前仿真时间里按照事件的优先级顺序进行排序。*活跃事件是优先级最高的事件。在活跃事件之间,它们的执行顺序是随机的。阻塞赋值(=)、连续赋值(assign)以及非阻塞赋值的右式计算等都属于活跃事件。,例10正确的用非阻塞赋值来描述时序逻辑的设计风格#2modulepipen2(q3,d,clk);output7:0q3;input7:0d;inputclk;reg7:0q3,q2,q1;always(posedgeclk)beginq3=q2;q2=q1;q1=d;endendmodule,例11正确的用非阻塞赋值来描述时序逻辑的设计风格#3modulepipen3(q3,d,clk);output7:0q3;input7:0d;inputclk;reg7:0q3,q2,q1;always(posedgeclk)q1=d;always(posedgeclk)q2=q1;always(posedgeclk)q3=q2;endmodule,例12正确的用非阻塞赋值来描述时序逻辑的设计风格#4modulepipen4(q3,d,clk);output7:0q3;input7:0d;inputclk;reg7:0q3,q2,q1;always(posedgeclk)q2=q1;always(posedgeclk)q3=q2;always(posedgeclk)q1=d;endmodule,例题总结,四种阻塞赋值设计方式中有一种可以保证仿真正确四种阻塞赋值设计方式中有三种可以保证综合正确四种非阻塞赋值设计方式全部可以保证仿真正确四种非阻塞赋值设计方式全部可以保证综合正确虽然在一个always块中正确的安排赋值顺序,用阻塞赋值也可以实现移位寄存器时序流水线逻辑。但是,用非阻塞赋值实现同一时序逻辑要相对简单,而且,非阻塞赋值可以保证仿真和综合的结果都是一致和正确的。因此建议大家在编写Verilog时序逻辑时要用非阻塞赋值的方式。,时序反馈移位寄存器建模,线性反馈移位寄存器(LinearFeedbackShift-Register简称LFSR)是带反馈回路的时序逻辑。,modulelfsrb1(q3,clk,pre_n);outputq3;inputclk,pre_n;regq3,q2,q1;wiren1;assignn1=q1q3;always(posedgeclkornegedgepre_n)if(!pre_n)beginq3=1b1;q2=1b1;q1=1b1;end,elsebeginq3=q2;q2=n1;q1=q3;endendmodule,线性反馈移位寄存器,RTL级电路,思考:真正的LFSR电路图是什么样子?,用阻塞赋值描述的线性反馈移位寄存器,其功能正确,但模型的含义较难理解。modulelfsrb2(q3,clk,pre_n);outputq3;inputclk,pre_n;regq3,q2,q1;always(posedgeclkornegedgepre_n)if(!pre_n)q3,q2,q1=3b111;elseq3,q2,q1=q2,(q1q3),q3;endmodule把所有赋值弄到一个等式的方式(one-lineequations)来避免使用临时变量编码显得更难于理解尤其当涉及的表达式更大更长时,编写代码和调试都变得比较困难,因此不鼓励使用这种风格,用非阻塞语句描述的LFSR,可综合,其功能正确。,modulelfsrb1(q3,clk,pre_n);outputq3;inputclk,pre_n;regq3,q2,q1;wiren1;assignn1=q1q3;always(posedgeclkornegedgepre_n)if(!pre_n)beginq3=1b1;q2=1b1;q1=1b1;end,elsebeginq3=q2;q2=n1;q1=q3;endendmodule,RTL级电路,例用非阻塞语句描述的LFSR,可综合其功能正确。modulelfsrn2(q3,clk,pre_n);outputq3;inputclk,pre_n;regq3,q2,q1;always(posedgeclkornegedgepre_n)if(!pre_n)q3,q2,q1=3b111;elseq3,q2,q1=q2,(q1q3),q3;endmodule,移位寄存器设计,1含同步预置功能的移位寄存器设计REG86:0=REG87:1;,工作时序图,模式可控的移位寄存器设计,2使用移位操作符设计移位寄存器,移位寄存器的RTL图,阻塞赋值及一些简单的例子,例13moduledffb(q,d,clk,rst);outputq;inputd,clk,rst;regq;always(posedgeclk)if(rst)q=1b0;elseq=d;endmodule,虽然可行也很简单,但我们不建议这种用阻塞赋值来描述D触发器模型的风格。如果要把所有的模块写到一个always块里,是可以采用阻塞赋值得到正确的建模、仿真并综合成期望的逻辑。但是,这种想法将导致使用阻塞赋值的习惯,而在较为复杂的多个always块的情况下可能会导致竞争冒险,例14使用非阻塞赋值来描述D触发器是建议使用的风格moduledffx(q,d,clk,rst);outputq;inputd,clk,rst;regq;always(posedgeclk)if(rst)q=1b0;elseq=d;endmodule,小结,从上面介绍的移位寄存器的例子以及LFSR的例子,建议使用非阻塞赋值实现时序逻辑。而用非阻塞赋值语句实现锁存器也是最为安全的。原则1:时序电路建模时,用非阻塞赋值。原则2:锁存器电路建模时,用非阻塞赋值。,组合逻辑使用阻塞赋值,用Verilog可以有很多种方法为组合逻辑建模,但是当使用always块来为组合逻辑建模时,应该使用阻塞赋值(blockingassignment)。如果在某个always块里面只有一个赋值(表达),使用阻塞或者非阻塞赋值都可以正确工作。但是如果您对养成好的编码习惯有兴趣的话,还是要“总是用阻塞赋值对组合逻辑建模”。对于简单的组合alwasys块不仅可以用于时序逻辑,也可以用于组合逻辑,但是当always块中有多个赋值语句时使用了不含延迟(delay)的非阻塞赋值会造成仿真不正确,或者要使仿真正确您需要另外的添加敏感事件列表(sensitivitylistentries),和“多输入路径”(multiplepasses)来贯穿always块以使得仿真正确。因而从仿真的时间效率角度看也不合算。,例moduleao4(y,a,b,c,d);outputy;inputa,b,c,d;regy,tmp1,tmp2;always(aorborcord)begintmp1=aendendmoduley输出建立在3个依次执行的顺序上。由于非阻塞赋值的LHS变量值更新是在对RHS表达式估值之后,所以tmp1和tmp2的值仍然是该always块上一个输入口的值而不是在这一个仿真时间步(simulationtimestep)结束时被更新的值。因此y的值将受旧的tmp1和tmp2影响,而不是这次扫描过的always块内被更新的值。,例moduleao5(y,a,b,c,d);outputy;inputa,b,c,d;regy,tmp1,tmp2;5always(aorborcordortmp1ortmp2)begintmp1=aendendmodule,不同之处在于tmp1和tmp2被添加到事件列表中去了,当非阻塞赋值更新LHS变量时,always块将会“自触发”并使用最新的tmp1和tmp2来更新y输出。现在y输出值正确了因为增加使用了两条“登入路径”(twopasses)贯穿整个always块。使用更多的“登入路径”来贯穿always块等于降低仿真器的性能,因此如果可以有合理的一些代码变化可以取代这种用法的话,就尽量避免这种用法。,例使用阻塞赋值实现组合逻辑是推荐使用的编码风格。moduleao2(y,a,b,c,d);outputy;inputa,b,c,d;regy,tmp1,tmp2;always(aorborcord)begintmp1=aendendmodule,小结,原则3:用always块描述组合逻辑时,应采用阻塞赋值语句,时序和组合的混合逻辑使用非阻塞赋值,有时候将简单的组合逻辑和时序逻辑写在一起很方便。当把组合逻辑和时序逻辑写到一个always块中时,应遵从时序逻辑建模的原则,使用非阻塞赋值,如例所示。例2在一个always块中同时实现组合逻辑和时序逻辑modulenbex2(q,a,b,clk,rst_n);outputq;inputclk,rst_n;inputa,b;regq;always(posedgeclkornegedgerst_n)if(!rst_n)q=1b0;/时序逻辑elseq=ab;/异或,为组合逻辑endmodule,例将组合和时序逻辑分别写在两个always块中,一个是纯粹的时序逻辑(使用非阻塞赋值),另一个是纯粹的组合逻辑(使用阻塞赋值)建模modulenbex1(q,a,b,clk,rst_n);outputq;inputclk,rst_n;inputa,b;regq,y;always(aorb)y=ab;always(posedgeclkornegedgerst_n)if(!rst_n)q=1b0;elseq=y;endmodule,小结,原则4:在同一个always块中描述时序和组合逻辑混合电路时,用非阻塞赋值。,其它混合“阻塞”与“非阻塞”赋值建模方针,Verilog语法并没有禁止将阻塞和非阻塞赋值自由地组合在一个always块里。虽然Verilog语法是允许这种写法的,但我们不建议在可综合模块的编写中采用这种风格,例24在always块中同时使用阻塞和非阻塞赋值的例子。moduleba_nba2(q,a,b,clk,rst_n);outputq;inputa,b,rst_n;inputclk;regq;always(posedgeclkornegedgerst_n)begin:ffregtmp;if(!rst_n)q=1b0;elsebegintmp=aendendendmodule,仿真和综合都将是正确的,因为“阻塞”与“非阻塞”赋值不是针对同一个变量来的。尽管这可以“正常工作”,但是不推荐这种风格。,例对同一变量既进行阻塞赋值,又进行非阻塞赋值有时会产生综合错误。moduleba_nba6(q,a,b,clk,rst_n);outputq;inputa,b,rst_n;inputclk;regq,tmp;always(posedgeclkornegedgerst_n)if(!rst_n)q=1b0;/对q进行阻塞赋值elsebegintmp=a/对q进行非阻塞赋值endendmodule,小结,原则5:不要在同一个always块中同时使用阻塞和非阻塞赋值,对同一变量进行多次赋值,在一个以上always块中对同一个变量进行多次赋值可能会导致竞争冒险,即使使用非阻塞赋值也可能产生竞争冒险。在下例中,两个always块都对输出q进行赋值。由于两个always块执行的顺序是随机的,所以仿真时会产生竞争冒险,例25使用非阻塞赋值语句,由于两个always块对同一变量q赋值产生竞争冒险的程序:modulebadcode1(q,d1,d2,clk,rst_n);outputq;inputd1,d2,clk,rst_n;regq;always(posedgeclkornegedgerst_n)if(!rst_n)q=1b0;elseq=d1;always(posedgeclkornegedgerst_n)if(!rst_n)q=1b0;elseq=d2;endmodule,在synplifyPro下综合,产生错误信息:E:Onlyonealwaysblockmayassignagivenvariableq,综合出现的错误,小结,原则6:严禁在多个always块中对同一个变量赋值,常见的对于非阻塞赋值的误解,1非阻塞赋值和$display误解1:“使用$display命令不能用来显示非阻塞语句的赋值”事实是:非阻塞语句的赋值在所有的$display命令执行以后才更新数值2#0延时赋值误解2:“0延时把赋值强制到仿真时间步的末尾”事实是:0延时将赋值事件强制加入停止运行事件队列中。,例moduledisplay_cmds;rega;initial$monitor($monitor:a=%b,a);initialbegin$strobe($strobe:a=%b,a);a=0;a=1;$display($display:a=%b,a);#1$finish;endendmodule,下面是上面模块的仿真结果说明$display命令的执行是安排在活动事件队列中,但排在非阻塞赋值数据更新事件之前。$display:a=0$monitor:a=1$strobe:a=1,例28modulenb_schedule1;rega,b;initialbegina=0;b=1;a=b;b=a;$monitor(%0dns:$monitor:a=%bb=%b,$stime,a,b);$display(%0dns:$display:a=%bb=

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论