二者区别:
阻塞(=)和非阻塞(<=)赋值的本质区别:
阻塞:在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句;
非阻塞:当前语句的执行不会阻塞下一语句的执行。
先举一个阻塞赋值的例子:
always @(posedge Clk)
begin
C1 = D;
C2 = C1;
C3 = C2;
end
always语句块对Clk的上升沿敏感,当发生Clk 0~1的跳变时,执行该always语句。
在begin...end语句块中所有语句是顺序执行的,而且最关键的是,阻塞赋值是在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句的。
在本例中,D的值赋给C1以后,再执行C2 = C1;同样在Q2的值更新以后,才执行C3 = C2。这样,最终的计算结果就是C3 = D。
所有的语句执行完以后,该always语句等待Clk的上升沿,从而再一次触发begin...end语句。
再举一个非阻塞赋值的例子:
always @(posedge Clk)
begin
C1 <= D;
C2 <= C1;
C3 <= C2;
end
always语句块对Clk的上升沿敏感,当发生Clk 0~1的跳变时,执行该always语句。
首先执行C1 <= D,产生一个更新事件,将D的当前值赋给C1,但是这个赋值过程并没有立刻执行,而是在事件队列中处于等待状态。
然后执行C2 <= C1,同样产生一个更新事件,将C1的当前值(注意上一语句中将D值赋给C1的过程并没有完成,C1还是旧值)赋给C2,这个赋值事件也将在事件队列中处于等待状态。
再执行C3 <= C2,产生一个更新事件,将C2的当前值赋给C3,这个赋值事件也将在事件队列中等待执行。
这时always语句块执行完成,开始对下一个Clk上升沿敏感。
那么什么时候才执行那3个在事件队列中等待的事件呢?只有当当前仿真时间内的所有活跃事件和非活跃事件都执行完成后,才开始执行这些非阻塞赋值的更新事件。这样就相当于将D、C1和Q2的值同时赋给了C1、C2和C3。
适用条件:
(1)时序电路建模时,采用非阻塞赋值。
(2)用always块来建立组合逻辑模型时,采用阻塞赋值。
(3)在同一个always块内建立时序和组合逻辑电路时,采用非阻塞赋值。
(4)在同一个always块中不要既要用非阻塞赋值又用阻塞方式赋值。
(5)不要在一个以上的always块中为同一个变量赋值。