tag 标签: 非阻塞赋值

相关博文
  • 热度 23
    2016-4-10 13:51
    1524 次阅读|
    1 个评论
       Verilog HDL  语言中存在两种赋值语言 :非阻塞型赋值语句,阻塞型赋值语句            在Verilog HDL中阻塞赋值"="和非阻塞赋值"="有着很大的不同.个人认为,作为初学者要掌握可综合风格的Verilog模块编程的8个原则,在综合布局布线的仿真中避免出现竞争冒险现象。(关于竞争冒险,后续会有单独章节记录)   (1)  时序电路建模时,用非阻塞赋值。   (2)  锁存器电路建模时,用非阻塞赋值。   (3)  用always块建立组合逻辑模型时,用阻塞赋值。   (4)  在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值。   (5)  在同一个always块中不要既用非阻塞赋值又用阻塞赋值。   (6)  不要在一个以上的always块中为同一个变量赋值。   (7)  用$strobe系统任务来显示用非阻塞赋值的变量值。   (8)  在赋值时不要使用 #0延时。     用"="或者是"="实际上对应的是不同的硬件电路 1.  非阻塞型语句 以赋值操作符“=”来标识的赋值操作称为“非阻塞型过程赋值( NonblockingAssignment)”。 非阻塞型过程赋值语句的特点是: ( 1) 在 begin-end 串行语句块中,一条非阻塞过程语句的执行不会阻塞下一条语句的执行,也就是说在本条非阻塞型过程赋值语句对应的赋值操作执行完之前,下一条语句也可以开始执行。 ( 2) 仿真过程在遇到非阻塞型过程赋值语句后首先计算其右端赋值表达式的值,然后等到仿真时间步结束时再将该计算结果赋值变量。也就是说,这种情况下的赋值操作是在同一仿真时刻上的其他普通操作结束后才得到执行的   下面看一下例程非阻塞赋值的代码和仿真: module non_block(clk,rst_n,a,b,c,out); input clk; input rst_n;// _n低电平有效 input a,b,c; output reg  out; /*output reg的使用.reg是寄存器型变量的意思,一般在用时序逻辑编程时定义.而output代表此变量为输出。实际上两者并没有直接联系,但是如果这个变量既是时序逻辑(寄存器型)变量又要求输出,就既需要output,也需要reg...一般always@语句中赋值的变量都要声明为reg型*/ reg   d; always@(posedge clk or negedge rst_n) if(!rst_n) out = 2'b0;//三位数相加以1+1+1=3为例 转化为二进制 位宽两位 else begin d = a+b; out = d + c; end endmodule RTL视图: 仿真结果: 下面我们改变一下代码 always@(posedge clk or negedge rst_n) if(!rst_n) out = 2'b0;//三位数相加以1+1+1=3为例 转化为二进制 位宽两位 else begin //d = a+b; out = d + c;//注意改变后的代码 d = a+b; end RTL视图: 从上面两张RTL视图中我们可以看到,在非阻塞赋值语句改变代码后,RTL结果不变 仿真结果:   2. 阻塞型语句    以赋值操作符“ =”来标识的赋值操作称为“阻塞型过程赋值( blocking Assignment)”。非阻塞型过程赋值语句的特点是: ( 1) 串行块( begin-end)中的各条阻塞型过程赋值语句将以它们在顺序块后排 列次序依次得到执行。 ( 2)阻塞型过程赋值语句的执行过程是:首先计算右端赋值表达式的值,然后 立即将计算结果赋值给“ =”左端的被赋值变量。   阻塞型过程赋值语句的这两个特点表明:仿真进程在遇到阻塞型过程赋值 语句时将计算表达式的值并立即将其结果赋给等式左边的被赋值变量;在串行语 句块中,下一条语句的执行会被本条阻塞型过程赋值语句所阻塞,只有在当前这 条阻塞型过程赋值语句所对应的赋值操作执行完后下一条语句才能开始执行。 下面看一下例程阻塞赋值的代码和仿真: always@(posedge clk or negedge rst_n) if(!rst_n)     out = 2'b0;//三位数相加以1+1+1=3为例 转化为二进制 位宽两位 else begin     d = a+b;     out = d + c; end RTL视图: 仿真结果: 下面我们改变一下代码 if(!rst_n)     out = 2'b0; else begin     //d = a+b;     out = d + c;//注意改变后的代码     d = a+b; end RTL视图: 改变后与改变前的图明显不同,多出一个寄存器,我们可以看到,阻塞语句中最后生成结果与程序语句的先后顺序很重要的关联 仿真结果:   以上的仿真代码: `timescale 1ns/1ns `define clock_period 20   //定义时钟 module block_tb; reg clk; reg rst_n; reg a,b,c; wire  out;                  block block0(.clk(clk),.rst_n(rst_n),.a(a),.b(b),.c(c),.out(out)); //block block0(clk,rst_n,a,b,c,out); initial clk = 1; always#(`clock_period/2) clk = ~clk; 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 注:例化中注释的部分是Augus失误所写成的代码,但是仿真结果全都都对,Augus当时像发现"新大陆"一样激动,在此解释一下,正确的例化: block block0(.clk(clk),.rst_n(rst_n),.a(a),.b(b),.c(c),.out(out)); //block block0(clk,rst_n,a,b,c,out);   而我失误写的虽然对了,原因是该程序相对简单且端口较少,且 默认来模块定义的接口来一一对应, 例化(XXX)的顺序和定义的端口顺序相同,所以侥幸未出现失误   由于本人能力有限,出错之处的请各位给予帮助. 谢谢! PS:  前期多为整理(博主使用例程自己学习过程中的理解记录的笔记)  更多资料参考                 发烧友小梅哥专版 http://bbs.elecfans.com/zhuti_fpga_1.html                     梦翼师兄的炼狱传奇
  • 热度 16
    2015-3-14 20:56
    844 次阅读|
    0 个评论
      阻塞和非阻塞语句作为verilog HDL语言的最大难点之一,一直困扰着FPGA设计者,即使是一个颇富经验的设计工程师,也很容易在这个点上犯下一些不必要的错误。阻塞和非阻塞可以说是血脉相连,但是又有着本质的差别。理解不清或运用不当,都往往会导致设计工程达不到预期的效果,而其中的错误又很隐晦。下面我给大家谈谈阻塞和非阻塞语句的本质区别和在FPGA设计中的不同运用。   阻塞语句   顾名思义,即本条语句具有影响下一条语句的作用,在同一个进程always中,一条阻塞赋值语句的执行是立刻影响着下条语句的执行情况和结果。如果该条语句没有执行完,那么下条语句不可能进入执行状态的,因此,从字面层上理解,该条语句阻塞了下面语句的执行。阻塞语句最能体现verilog HDL和C语言之间的血缘关系,比如,在时钟沿触发的always进程里,若先执行b=c,再执行a=b,那么本质上,在一个时钟沿触发里面,a=c成立,即是说,不要b变量,直接在进程里赋值a=c,结果是一样的。这和c语言中b=c,a=b性质相同。   非阻塞语句   非阻塞语句应该来说,更能体现硬件电路的特点。这正是非阻塞语句广泛应用于时序逻辑电路的原因。接上面的例子,如果在一个时钟沿触发的always进程里面,b=c,a=b那么就不可能直接在进程里面赋值a=c.因为c的值要经过两个时钟延迟才传到a里面,即c若从0变为1,那么要经过两个clk上升沿才传到a,a的值才从0变为1。两次赋值正是体现了两个时钟延迟的特点。这种特点即是非阻塞语句非阻塞的的原因导致的,就是说,a=b,不会因为b=c没有执行完毕而不执行,只要时钟触发进程,那么a=b,b=c同时执行。所以,如果c为 1,b为0,a为1的话,那么在在非阻塞语句的进程里面,一个时钟沿到来,由于他们之间是同时执行的,所以把c的1赋给了b,把b的0赋给了a,但是在阻塞语句里面,c的1先给了b,然后b把新赋值的1又给了a,那么a在一个时钟之后即变成了1。(在一次触发进程里,无论是阻塞和非阻塞语句,每条语句只能执行一次)   所以从上面的介绍里面,可以看出,阻塞语句是顺序执行的,而非阻塞语句是同时执行的,那么,如何在设计里面运用好阻塞语句和非阻塞语句呢,总体上来讲,遵循大体原则:阻塞语句运用在组合逻辑电路设计里面,非阻塞语句运用在时序逻辑电路设计里面。但是一般来讲,一个设计往往包含着组合逻辑和时序逻辑。可以再细分为以下几个情况,并可以用阻塞语句和非阻塞语句不同的设计来区别讨论它们之间的优缺点,进一步理解清楚。。。。。。(最直观的说法就是如下仿真一下:观察out1~out4的变化,就明白了! `timescale 1ns/100ps module test1(); reg clk; reg sigin; reg out1; reg out2; reg out3; reg out4; //assign #10 out3 = sigin; always #10 clk=~clk; always #70 sigin = ~sigin; initial begin sigin = 1'b0; clk= 1'b0; out1 =1'b0; out2 =1'b0; end always @(sigin) begin $display('%d',$time); out1=sigin; out2= out1; out3 = sigin; out4 = out3; $display('%d',$time); end endmodule #1: 当为时序逻辑建模,使用“非阻塞赋值”。 #2: 当为锁存器(latch)建模,使用“非阻塞赋值”。 #3: 当用always块为组合逻辑建模,使用“阻塞赋值” #4: 当在同一个always块里面既为组合逻辑又为时序逻辑建模,使用“非阻塞赋值”。 #5: 不要在同一个always块里面混合使用“阻塞赋值”和“非阻塞赋值”。 #6: 不要在两个或两个以上always块里面对同一个变量进行赋值。 #7: 使用$strobe以显示已被“非阻塞赋值”的值。 #8: 不要使用#0延迟的赋值。
  • 热度 18
    2013-9-16 10:56
    1149 次阅读|
    0 个评论
      阻塞和非阻塞语句作为verilog HDL语言的最大难点之一,一直困扰着FPGA设计者,即使是一个颇富经验的设计工程师,也很容易在这个点上犯下一些不必要的错误。阻塞和非阻塞可以说是血脉相连,但是又有着本质的差别。理解不清或运用不当,都往往会导致设计工程达不到预期的效果,而其中的错误又很隐晦。下面我给大家谈谈阻塞和非阻塞语句的本质区别和在FPGA设计中的不同运用。   阻塞语句   顾名思义,即本条语句具有影响下一条语句的作用,在同一个进程always中,一条阻塞赋值语句的执行是立刻影响着下条语句的执行情况和结果。如果该条语句没有执行完,那么下条语句不可能进入执行状态的,因此,从字面层上理解,该条语句阻塞了下面语句的执行。阻塞语句最能体现verilog HDL和C语言之间的血缘关系,比如,在时钟沿触发的always进程里,若先执行b=c,再执行a=b,那么本质上,在一个时钟沿触发里面,a=c成立,即是说,不要b变量,直接在进程里赋值a=c,结果是一样的。这和c语言中b=c,a=b性质相同。   非阻塞语句   非阻塞语句应该来说,更能体现硬件电路的特点。这正是非阻塞语句广泛应用于时序逻辑电路的原因。接上面的例子,如果在一个时钟沿触发的always进程里面,b=c,a=b那么就不可能直接在进程里面赋值a=c.因为c的值要经过两个时钟延迟才传到a里面,即c若从0变为1,那么要经过两个clk上升沿才传到a,a的值才从0变为1。两次赋值正是体现了两个时钟延迟的特点。这种特点即是非阻塞语句非阻塞的的原因导致的,就是说,a=b,不会因为b=c没有执行完毕而不执行,只要时钟触发进程,那么a=b,b=c同时执行。所以,如果c为 1,b为0,a为1的话,那么在在非阻塞语句的进程里面,一个时钟沿到来,由于他们之间是同时执行的,所以把c的1赋给了b,把b的0赋给了a,但是在阻塞语句里面,c的1先给了b,然后b把新赋值的1又给了a,那么a在一个时钟之后即变成了1。(在一次触发进程里,无论是阻塞和非阻塞语句,每条语句只能执行一次)   所以从上面的介绍里面,可以看出,阻塞语句是顺序执行的,而非阻塞语句是同时执行的,那么,如何在设计里面运用好阻塞语句和非阻塞语句呢,总体上来讲,遵循大体原则:阻塞语句运用在组合逻辑电路设计里面,非阻塞语句运用在时序逻辑电路设计里面。但是一般来讲,一个设计往往包含着组合逻辑和时序逻辑。可以再细分为以下几个情况,并可以用阻塞语句和非阻塞语句不同的设计来区别讨论它们之间的优缺点,进一步理解清楚。。。。。。(最直观的说法就是如下仿真一下:观察out1~out4的变化,就明白了! `timescale 1ns/100ps module test1(); reg clk; reg sigin; reg out1; reg out2; reg out3; reg out4; //assign #10 out3 = sigin; always #10 clk=~clk; always #70 sigin = ~sigin; initial begin sigin = 1'b0; clk= 1'b0; out1 =1'b0; out2 =1'b0; end always @(sigin) begin $display('%d',$time); out1=sigin; out2= out1; out3 = sigin; out4 = out3; $display('%d',$time); end endmodule #1: 当为时序逻辑建模,使用“非阻塞赋值”。 #2: 当为锁存器(latch)建模,使用“非阻塞赋值”。 #3: 当用always块为组合逻辑建模,使用“阻塞赋值” #4: 当在同一个always块里面既为组合逻辑又为时序逻辑建模,使用“非阻塞赋值”。 #5: 不要在同一个always块里面混合使用“阻塞赋值”和“非阻塞赋值”。 #6: 不要在两个或两个以上always块里面对同一个变量进行赋值。 #7: 使用$strobe以显示已被“非阻塞赋值”的值。 #8: 不要使用#0延迟的赋值。
相关资源