1. 程式人生 > 其它 >未聞verilog---時序模型

未聞verilog---時序模型

時序模型

分層事件列解釋了事件排程執行的順序和策略,但是它沒有很好的解釋模擬器是如何處理語句中的時序控制部分,所以需要學習時序模型。

模擬器的事件推進模型是時序模型,它反映了模擬時間如何推進以及事件如何排程。

敏感表:是模擬模型的輸入表,它由接受新值的元素組成,當輸入發生變化時,它能顯示哪些輸入的變化會導致模擬模型的執行。

扇出表:由將產生新值的元素組成,他能表示當一個事件發生時需要計算哪些元素。

時序模型分為:門級時序模型過程時序模型

門級時序模型

Verilog門級時序模型主要用於所有的連續賦值語句,過程連續賦值語句,門原語,使用者自定義原語。

任意時刻任意輸入發生變化時,門例項將重新計算他們的輸出,如果輸出有變化,以後可能會產生一個新的事件

。所有的輸入對變化總是敏感的,這種變化又將導致模擬模型的執行。(輸入有變化,將啟用門級更新事件)

假設存在一個表示門級時序模型的特定元素的一個事件已被排程,但尚未執行,如果該元素的輸出又導致產生一個新事件,那麼撤銷先前已排程的事件,並排程新的事件。

所以Verilog門級模型具有慣性延時。門級時序模型非常精確地模擬了電路中的慣性延時。

過程時序模型

過程時序模型的敏感性依賴於控制的上下文,它不是對任何時刻的任何變化都敏感。一般來說,Initial和always語句只對輸入的一個子集(輸入的一部分)敏感,這種敏感性是隨著模擬執行時間而改變的,因此這些敏感元素是根據行為模型的當前執行部分來確定的。比如always語句對@ 符號後面括號裡的變數敏感。(如果沒有執行到@敏感列表處,就不會對敏感列表中的元素敏感)

事件排程方面,假設一個暫存器的一個更新事件已經被排程,如果再排程一個暫存器的另一個更新事件,即使再同一個時刻,前一個事件也不會被取消。所以,一個實體(比如暫存器)的事件列表中可能有多個事件,如果同時有幾個更新事件,那麼他們的執行順序是不確定的(如果有begin...end塊存在則約束了語句執行的順序,當然這個時候更新事件就不同時了,這裡的同時應該指的是不同快之間對同一個暫存器的更新事件)。

總而言之,門級過程模型會在新的事件啟用時,會撤銷先前的已排程但未執行的事件。過程結構語句則先前的事件和之後的事件會並存。

一般來說,門級時序模型和過程時序模型定義了語言中的兩大類元件:門機時序模型主要用於對組合邏輯建模,而過程時序模型主要用於對時序邏輯建模,例如觸發器和鎖存器。

慣性延遲和傳輸延時

前面提到了門級時序模型非常精確地模擬了電路中的慣性延時,那什麼是慣性延時,什麼是傳輸延時?

電路中存在著兩種延時:慣性延時(Inertial delay)和傳輸延時(Transport delay)

慣性延遲

假設一個與非閘電路,門延時是5ns,那麼任何小於這個延時值的輸入變化都不會對輸出造成影響。

由於輸入變化過快,小於門本身的延時值,導致輸出無響應的特性,被稱為電路的慣性延時,也就是說電路具有一定的慣性或者惰性。

一般來說,Verilog的門級時序模型是具有純慣性延時的模型。

傳輸延時

假設存在一條延時5ns的傳輸線(訊號通過傳輸線也需要時間),輸入端的任何變化經過延時值都會在輸出端顯示出來,這種叫做電路的**傳輸延時。 **(就是說不管輸入的變化速度如何,都能在輸出端反映出來)

對非阻塞賦值的右式(RHS)加延遲引數,可以模擬傳輸延時

延時

連續賦值加延時

注意:對於連續賦值加延時,延時只能加在assign與變數之間,不能放在等號後面。

這裡舉個例子

assign #50 a = b;

這裡的意思是將b的值延遲50個時間單位賦給a。

但是通過模擬可以看出,如果b的變化時間小於50個時間單位,b的變化並不能在a上顯示出來,只有當b的變化時間大於50個時間單位,才能在50個時間單位後顯示出來。

分析一下,比如b的變換時間是30個時間單位。因為連續賦值是門級時序模型,無論c何時發生變化,都會以及產生並執行一個計算事件,計算等號右邊的值,同時產生一個更新事件,把值賦給a,但並沒有執行,只是把這一更新事件排程到當前模擬以後50個時間單位去執行。

前面我們說過,門級時序模型,新啟用的事件會撤銷之前已經啟用但沒有執行的事件。當b從低電平拉高到高電平,這時啟用一個事件將高電平(1)賦給a,但沒有立即執行,需要等到50個時間單位之後。當過了30個時間單位,b的電平從高電平拉到低電平,這時有激活了一個事件將低電平(0)賦給啊,但沒有立即執行,需要等到50個事件單位之後,因為之前存在一個沒有執行的事件,所以這個把a賦值為0的事件將把a賦值為1的事件給撤銷掉,所以當b拉高電平之後50個時間單位時,a的值並沒有拉高,因為這個事件被把a賦值為0的事件給撤銷掉了。所以最後a的值看起來並沒有將b的變化延遲50個單位輸出。

如果b的變化時間為80個時間單位,當b從低電平拉高為高電平時,激活了一個事件將高電平(1)賦值給a,這個事件被啟用但沒有立即執行,等過了50個事件單位,才執行,從開始計數80個時間單位,b從高電平拉低,激活了將a賦值為0的事件,事件沒有立即執行,等待了50個事件單位才執行將a賦值為0,這時距一開始b拉高已經過了150個時間單位,所以從外面看看來,a將b80個時間單位的變化輸出出來了。

所以連續賦值加延時將高於本身延時的訊號變化顯示出來,但小於本身延時的訊號變化卻不能顯示出來。

阻塞賦值加延時

對於阻塞賦值加延時,有兩種方式

always @(a or b) 
    begin
        #5 sum = a + b; //語句A
    end
always @(a or b)
    begin
        sum = #5 a + b; //語句B
    end

對於語句A,假設現在的時間為T,當a或b發生變化時,always塊被觸發,導致always語句開始執行,然後遇到了#5,立刻將該always程序掛起(這裡的掛起是因為遇到了延時),等5個時間單位後,即T+5時刻,再將這個時刻(T+5)的a和b相加賦值給sum。這時的sum為T+5時刻的a與b之和。在這期間由於延時將always塊掛起,所以a和b的任何變化都被忽略。

對於語句B,假設現在的時間為T,當a或b發生變化時,always塊被觸發,導致always語句開始執行,先將T時刻的a和b進行求和,由於存在#5,所以需要延遲5個時間單位再將值賦值給sum,因為阻塞賦值會將塊內的其他語句阻塞,所以在等待延時時會將always塊掛起(這裡的掛起是因為阻塞賦值不能完成更新,阻塞了整個塊),等5個時間單位後(T+5時刻)將T時刻的a和b之和賦值給sum。因為中間always塊被掛起,所以在這段時間裡a和b的任何變化都被忽略。

(當延時加在語句的前面,會阻塞整個塊,之後等延時結束在用當前的資料進行語句的運算,當延時加在等號之後,則先用當前時刻的資料計算後面的計算式,再延時,之後等延時結束再更新左值)

從上面的分析可以看出,阻塞賦值加延時,中間輸入變數的任何變化都被忽略掉,不能模擬任何電路中的延時型別,容易被忽視,也容易一出錯,不建議使用。

非阻塞賦值加延時

對於非阻塞賦值加延時,有兩種方式

always @(a or b) 
    begin
        #5 sum <= a + b; //語句A
    end
always @(a or b)
    begin
        sum <= #5 a + b; //語句B
    end

對於語句A,假設現在的時間為T,當a或b發生變化時,always塊被觸發,導致always語句開始執行,然後遇到了#5,立刻將該always程序掛起(這裡的掛起是因為遇到了延時),等5個時間單位後,即T+5時刻,再將這個時刻(T+5)的a和b相加賦值給sum。這時的sum為T+5時刻的a與b之和。在這期間由於延時將always塊掛起,所以a和b的任何變化都被忽略。

對於語句B,假設現在的時間為T,當a或b發生變化時,always塊被觸發,導致always語句開始執行,先將T時刻的a和b進行求和,由於存在#5,所以需要延遲5個時間單位再將值賦值給sum,因為非阻塞賦值不會將塊內的其他語句阻塞,所以在等待延時時always塊將執行結束,等5個時間單位後(T+5時刻)將T時刻的a和b之和賦值給sum。因為中間always塊已經結束,always塊再次恢復對a和b的敏感,所以在這段時間裡a和b的任何變化都不能被忽略,由前面結構時序模型的特點可以知道,在等待延時的這段時間內,如果a和b再次發生變化將再次觸發always塊,會產生新的更新事件,新的事件不會撤銷前面的事件,會排在前面事件的後面,所以輸入訊號任何時間長度的變化都會在輸出上有所反應,所以對非阻塞賦值的右值加延時可以準確的模擬出電路中的傳輸延時。

(對於非阻塞賦值來說,在右值前面加延時只會使非阻塞賦值的左值更新被掛起,不會掛起整個語句,也不會阻塞後面語句的執行)

參考 《輕鬆成為設計高手》