對於Verilog 初學者來說,阻塞賦值與非阻塞賦值應該要區別一下子,我估計對於這兩種賦值方式的應用解說,什么時候該用阻塞賦值,什么時候該用非阻塞賦值,通常見到的一句話是,時序邏輯里面通常用非阻塞賦值,組合邏輯里面通常使用阻塞賦值。但是這必然是含糊不清的,也並不意味着時序邏輯里面就不可以阻塞賦值了,組合邏輯里面就不可以用非阻塞賦值了。所以我覺得有必要弄清楚一下阻塞賦值和非阻塞賦值的細微區別。
首先還是回歸下定義,所謂阻塞賦值,例如 a=b; 當這個賦值語句執行的時候是不允許有其它語句執行的,這就是阻塞的原因。而非阻塞賦值,例如a<=b;當這個賦值語句執行的時候是不阻礙其它語句執行的。對於FPGA來講,跟單片機相比(即使是高速單片機),它本身的優點是語句執行的並行性,而單片機語句執行是順序執行的。所以如果說我們要充分利用好FPGA這個優點,那么我們應該盡量使用非阻塞賦值。
下面我想從一個簡單的例子來淺析一下兩者的區別。
這是一個簡單的分頻程序,目的是將clk時鍾四分頻。Count初始值是0,(個人經驗認為的,因為verilog里面似乎沒法對變量進行初始化),然后第一個時鍾的上升沿到來時,count自加1后變成了1,if語句執行為假,然后第二個時鍾上升沿到來時,count又自加1變成了2,if語句執行條件為真,則執行if語句內的內容,將data_a數據翻轉,count重新賦值為0,所以該程序就是每兩個時鍾的上升沿,data_a數據翻轉一次,得到四分頻的效果。
下圖為仿真波形,是完全對得住分析的。
上面的程序用的是阻塞賦值,也就是 count執行自加1的時候,其它任何語句都是不能執行的,因此這里就有點想單片機里面的C語言了,一個順序執行的always塊。
如果把上面的程序賦值全改成非阻塞賦值,效果會怎樣呢?
首先我們先不作分析,先對比一下仿真波形。
從仿真波形來看,這個程序確變成了對clk時鍾的六分頻,顯然不是我們之前的思路分析結果。實際上它是這樣子執行的。
首先可以這樣理解,1、非阻塞賦值是always塊結束才賦值的,個人理解是程序見到always塊的結束標記end后才賦值,但是並不代表當程序最開始看到該語句時沒有任何動作,而是先把后面的值給計算出來放在一個寄存器中暫存,到了塊結束才賦值,比如上述中的先把count+1計算出來后,到了塊結束才把那個結果賦值給count。2、非阻塞賦值是並行執行的,因此不管有多少個always塊,不管每個always塊里面有多少條非阻塞賦值,它都是瞬間一塊並行執行的,互不干擾。
所以上面的程序就好分析了
Count初始值是0,第一個時鍾的上升沿到來時,count<=count+1 這條語句先不賦值(前面說了塊結束才賦值),但是count+1已經計算出來放在寄存器中存儲着,先執行的是if語句,if語句此時條件仍然是(count=0),條件為假,不執行if內部語句,接着遇到always塊結束標記end,這才執行count<=的賦值,count此時為1,然后第二個時鍾上升沿到來,同樣先執行if語句,條件仍然為假,然后再執行count自加1,count變為2,第三個時鍾上升沿到來,先執行if語句,條件滿足,至於此時 有三個非阻塞賦值的語句出現
count<=count+1;
data_a<=!data_a;
count<=0;
這三個語句按道理講也是並行執行的,但是,有兩個語句同時對count進行了賦值。。那么咋整呢,這點筆者尚未清楚,懇請達人解析,或者待日后筆者弄清楚在來看看了。。。