中科因仑“3+1”工程特种兵精英论坛

标题: Verilog中阻塞与非阻塞式赋值解惑 [打印本页]

作者: Fade_time    时间: 2014-2-20 11:06
标题: Verilog中阻塞与非阻塞式赋值解惑
     Verilog中阻塞与非阻塞式赋值是比较让初学者难以理解的两种赋值方式,今天我就来谈一谈它们之间的区别:使用过VHDL的朋友都知道,VHDL中信号使用非阻塞式 ,而变量类似于阻塞赋值    阻塞式过程赋值与非阻塞式过程赋值在Verilog中表示如下:
    c = a & b; 阻塞式过程赋值
    c <= a & b; 非阻塞式过程赋值
    两种赋值不会对语句本身的赋值有影响,但会影响以后对赋值结果的引用。一般的参考书中建议组合逻辑使用阻塞式,时序逻辑使用非阻塞式。且语句块中如果只有一条赋值语句,是阻塞还是非阻塞都没有任何不一样。
    非阻塞式过程赋值的赋值对象是在未来(即当前仿真时刻结束时)被赋值
    下面我们具体分析一下阻塞和非阻塞赋值的语义本质:
    阻塞:在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句;
    非阻塞:当前语句的执行不会阻塞下一语句的执行。
    先看阻塞赋值的情况:
    我们来看这段代码:
    always @(posedge Clk)        
      begin            
        Q1 = D;           
        Q2 = Q1;            
        Q3 = Q2;        
      end
    always语句块对Clk的上升沿敏感,当发生Clk 0~1的跳变时,执行该always语句。
    在begin...end语句块中所有语句是顺序执行的,而且最关键的是,阻塞赋值是在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句的。
    在本例中,D的值赋给Q1以后,再执行Q2 = Q1;同样在Q2的值更新以后,才执行Q3 = Q2。这样,最终的计算结果就是Q3 = D。
    所有的语句执行完以后,该always语句等待Clk的上升沿,从而再一次触发begin...end语句。
    接下来,再看看非阻塞赋值的情况。
    所谓非阻塞赋值,顾名思义,就是指当前语句的执行不会阻塞下一语句的执行
    always @(posedge Clk)        
     begin            
      Q1 <= D;            
      Q2 <= Q1;            
      Q3 <= Q2;        
     end
  首先执行Q1 <= D,产生一个更新事件,将D的当前值赋给Q1,但是这个赋值过程并没有立刻执行,而是在事件队列中处于等待状态。
  然后执行Q2 <= Q1,同样产生一个更新事件,将Q1的当前值(注意上一语句中将D值赋给Q1的过程并没有完成,Q1还是旧值)赋给Q2,这个赋值事件也将在事件队列中处于等待状态。
  再执行Q3 <= Q2,产生一个更新事件,将Q2的当前值赋给Q3,这个赋值事件也将在事件队列中等待执行。
  这时always语句块执行完成,开始对下一个Clk上升沿敏感。
  那么什么时候才执行那3个在事件队列中等待的事件呢?只有当当前仿真时间内的所有活跃事件和非活跃事件都执行完成后,才开始执行这些非阻塞赋值的更新事件。这样就相当于将D、Q1和Q2的值同时赋给了Q1、Q2和Q3。
  注:
    *仿真器首先按照仿真时间对事件进行排序,然后再在当前仿真时间里按照事件的优先级顺序进行排序。
    *活跃事件是优先级最高的事件。在活跃事件之间,它们的执行顺序是随机的。阻塞赋值(=)、连续赋值(assign)以及非阻塞赋值的右式计算等都属于活跃事件。






欢迎光临 中科因仑“3+1”工程特种兵精英论坛 (http://bbs.enlern.com/) Powered by Discuz! X3.4