數字門級電路可分為兩大類:組合邏輯和時序邏輯。鎖存器是組合邏輯和時序邏輯的一個交叉點,在后面會作為單獨的主題處理。
組合邏輯描述了門級電路,其中邏輯塊的輸出直接反映到該塊的輸入值的組合,例如,雙輸入AND門的輸出是兩個輸入的邏輯與。如果輸入值發生變化,輸出值將反映這一變化,組合邏輯的RTL模型需要反映這種門級行為,這意味著邏輯塊的輸出必須始終反映該邏輯塊當前輸入值的組合。
SystemVerilog有三種在可綜合RTL級別表示組合邏輯的方法:連續賦值語句、always程序塊和函數。接下來幾篇文章將探討每種編碼風格,并推薦最佳實踐編碼風格。
always和always_comb程序
組合邏輯的主要RTL建模構造是always過程,使用通用always關鍵字或RTL專用的always_comb關鍵字。這些always程序可以利用之前討論的強大的運算符編程語句,而連續賦值語句僅限于使用SystemVerilog運算符。一個簡單的組合邏輯加法器被建模為always程序和always_comb程序的例子如下:
可綜合組合邏輯的always程序
綜合編譯器支持always和always_comb程序。
當使用通用always程序時,綜合編譯器會施加一些編碼限制,RTL設計工程師必須了解并遵守這些限制。這些限制包括:
程序敏感列表應包括每個信號,其值可能影響組合邏輯的輸出。下一節詳細討論了敏感列表。
程序敏感列表必須對每個信號的所有可能值變化敏感。它不能包含限制對特定變化敏感性的posedge或negedge關鍵字。
程序應在零仿真時間內執行,并且不應包含任何形式的傳播延遲(包括使用#,@或者wait等控制語句)。
在組合邏輯程序中賦值的變量不應被任何其他程序或連續賦值語句所賦值。(允許在同一程序中進行多次賦值。)
對所有RTL組合邏輯進行零延遲建模。 |
最佳實踐指南7-3 |
---|
綜合器不允許@或wait等時間控制延遲,并將忽略#延遲。忽略#延遲可能會導致在仿真中驗證的RTL模型與綜合中忽略的門級實現不匹配。
使用通用always程序建模
使用RTL專用的always_comb程序對組合邏輯進行建模。不要在RTL模型中使用通用的always程序。 |
最佳實踐指南7-4 |
---|
RTL專用的always_comb會自動執行上面列出的編碼限制。敏感列表是推斷出來的,不允許@或wait時間控制,并且在always_comb程序中賦值的變量不能由其他程序或連續賦值。
雖然不推薦always程序用于RTL建模,但本文中討論了如何正確使用通用always程序對組合邏輯進行建模,因為這種通用程序在傳統的Verilog模型中很常見。
組合邏輯敏感列表。通用always程序需要一個敏感列表,以告知仿真器何時處理程序中的編程語句。敏感列表使用@(信號列表)形式指定,如下例所示:
敏感列表中的每個信號用逗號(,)分隔,如上例所示,或用or關鍵字分隔,如@(a or b or mode)。使用逗號(,)與或關鍵字or相比,沒有任何優點或缺點。一些工程師更喜歡逗號(,)分隔的列表,因為or關鍵字可能會被誤認為是邏輯or操作,而不僅僅是列表中信號之間的分隔符。
完整的敏感列表。對于組合邏輯,組合塊的輸出是該塊輸入的當前值的直接反映,為了對這種行為進行建模,當任何信號的值發生變化而影響程序輸出的值時,always程序需要執行其編程語句。組合always程序的輸入是程序中的語句讀取值的任何信號,在上面的加法器示例中,程序的輸入——程序中讀取的信號為:a、b和mode。
程序輸入與模塊輸入。組合邏輯程序的輸入可能與包含該程序的模塊的輸入端口不一致。模塊可能包含多個程序塊和連續賦值語句,因此,每個程序塊都有輸入端口。模塊也可能包含內部信號,在程序塊或連續賦值語句之間傳遞數值。這些內部信號將不包括在模塊端口列表中。
不完整的敏感列表-一個建模故障。
gotcha是一個編程術語,用于描述語法合法但性能不符合預期的代碼。一般的always程序允許犯這種類型的編碼錯誤。如果組合邏輯程序的一個或多個輸入被無意中從敏感列表中忽略,RTL模型也將被編譯,甚至可能看起來是正確的仿真。然而,完整的驗證表明,組合邏輯塊的輸出在一定時間段內不反映當前輸入值的組合。考慮下面的代碼片段:
如果mode改變,result的輸出將不會更新為新的操作結果,直到a或b改變值。在mode更改和a或b更改之間的時間內,result值不正確。
這種編碼錯誤在只讀取少數信號值的小型組合邏輯塊中是很明顯的,但對于更大、更復雜的邏輯塊來說,讀取10、20甚至幾十個信號并不罕見。當涉及這么多信號時,很容易在不經意間忽略敏感列表中的一個信號。在設計開發過程中修改always塊也很常見,比如在邏輯中添加另一個信號,但忘記將其添加到敏感列表中。這種編碼錯誤的一個嚴重危害是,許多綜合編譯器仍將這種不正確的RTL模型實現為門級組合邏輯,可能帶有一條容易忽略的警告消息,盡管綜合編譯器的實現可能是設計者的意圖,但他并不是RTL仿真期間所驗證的設計功能。因此,設計功能沒有被充分驗證,這可能會導致實際ASIC或FPGA運行時會出現錯誤。
過時的always@ 程序。IEEE 1364-2001標準(通常稱為Verilog-2001)試圖通過添加特殊標記來解決不完整敏感度列表的問題,該標記將自動推斷出完整的敏感列表,例如:
也可以用括號括起來,如@( )。與在組合邏輯敏感列表中顯式列出信號相比,@ 標記提供了更好的編碼風格。然而,這個標記有兩個問題。首先,綜合編譯器對組合邏輯建模施加了一些限制。使用@ 可以推斷出一個敏感度列表,但不強制執行用于組合邏輯建模的其他綜合規則。@ 的第二個問題是沒有推斷出完整的敏感度列表。如果一個組合邏輯程序調用一個函數,但沒有將函數中使用的所有信號作為函數參數傳入,則會推斷出一個不完整的敏感列表。
使用SystemVerilog中專用的always_comb程序自動推斷正確的組合邏輯敏感列表。不要使用過時的@*推斷敏感列表。 |
最佳實踐指南7-5 |
---|
Always_comb程序將推斷出準確的敏感列表,而不存在顯式列表的危害,或者@ 的推斷問題。always_comb過程也會強制執行綜合編譯器精確建模組合邏輯行為所需的編碼限制。
在20世紀80年代推出的最初的Verilog語言只有通用的always程序。雖然非常有用,但當用于RTL建模時,該過程的通用性有嚴重的局限性。作為一個通用程序,always可用于仿真組合邏輯、時序邏輯、鎖存邏輯和各種驗證過程。當綜合編譯器遇到always過程時,編譯器無法知道設計工程師打算對哪種類型的功能進行建模。相反,綜合編譯器必須分析過程的內容,并試圖推斷設計者的意圖。綜合很可能推斷出不同于工程師預期的功能類型。
通用always程序的另一個限制是,它不強制執行綜合編譯器為表示組合邏輯行為所需的RTL編碼規則。使用通用always程序的模型可能看起來仿真正確,但可能無法綜合成預期的功能,因此在綜合模型之前,必須重寫RTL模型并在仿真中重新驗證功能,從而導致工程時間損失。
使用RTL專用的always_comb程序建模
SystemVerilog引入了RTL專用的always程序,如always_comb,以解決通用always程序的局限性。下面的示例對前面顯示的算術邏輯單元功能進行建模,但使用always_comb而不是always,
在編寫RTL模型時,always_comb程序有很多好處:
自動推斷出完整的敏感列表。該列表是完全完整的,避免了@*推斷不完整敏感列表的極端情況。
不允許在always_comb過程中使用#、@或wait等延遲語句的執行,這是對使用零延遲程序的綜合指南的強制。在always comb中使用這些時間控件是一個錯誤,在RTL模型的編譯和布線過程中會發現這一錯誤。
在“always_comb”程序中賦值的任何變量都不能從另一個程序或連續賦值語句中賦值,這是綜合編譯器要求的限制。在RTL模型的編譯和布線過程中,會發現違反此綜合規則的編碼錯誤。
Always_comb的語義規則符合綜合編譯器對組合邏輯RTL模型的編碼限制。這些規則有助于確保因為驗證無法綜合的設計而浪費工程時間。
在仿真開始時自動評估。always_comb過程還有一個語義規則,是專門針對仿真使用。組合邏輯的行為是,輸出值代表該邏輯塊的輸入值的組合。對于通用always程序,為了觸發程序內賦值語句的執行,敏感列表中的信號必須發生值更改。如果敏感列表中的信號在仿真開始時均未改變值,則組合邏輯程序的輸出不會更新,以匹配該過程的輸入值。組合邏輯程序將繼續具有不正確的輸出值,直到敏感列表中的信號改變值。這個問題是一個RTL仿真故障,門級實現不會有這個問題。
RTL專用的always_comb程序解決了這個仿真故障。always_comb程序將在仿真開始時自動觸發一次,以確保程序中分配的所有變量準確反映仿真時間零點時程序輸入的值。
使用阻塞(組合邏輯)賦值
在為組合邏輯建模時,只使用阻塞賦值(=)。 |
最佳實踐指南7-6 |
---|
SystemVerilog有兩種形式的賦值運算符:阻塞賦值(=)和非阻塞賦值(<=)。這些賦值類型影響仿真更新賦值語句左側值的順序,相對于仿真時那一刻的任何其他仿真活動。阻塞賦值(=)立即更新左側的變量,使新值可供begin-end語句組中的后續語句使用。“即時更新”有效地仿真了組合邏輯數據流中的值傳播行為。
下面的代碼片段演示了通過組合邏輯程序塊中的多個賦值的組合邏輯數據流。
在這個過程中,變量sum立即更新為a+b的運算結果。sum的這個新值流到下一個語句,在那里新值被用于計算prod的新值。prod的這個新值然后流到下一行代碼,并用于計算result的值。
賦值語句的阻塞行為對于該數據流在零延遲RTL模型中正確仿真至關重要。每行代碼中的阻塞賦值都會阻塞下一行的求值,直到當前行用新值更新其左側變量,對后續每行求值代碼的阻塞才能確保每一行使用前一行分配的新變量值。
如果在上面的代碼段中不適當地使用了非阻塞賦值,在這些變量被更新為新值之前,則每個賦值都會使用其右側變量的先前值 。顯然這不是組合邏輯行為!然而,當使用非阻塞賦值時,綜合編譯器仍可能創建組合邏輯,導致在RTL仿真中驗證的行為與綜合后的實際門級行為不匹配。
避免組合邏輯程序中的意外鎖存
RTL建模中的一個常見問題是推斷代碼中的鎖存行為。SystemVerilog語言規則要求過程賦值的左側必須是某種類型的變量,Net(網絡)數據類型不允許出現在程序賦值的左側。這種對使用變量的要求可能會導致無意的鎖存,這是純組合邏輯的目的。當觸發非時鐘always程序(即組合邏輯程序)且不對該程序使用的變量進行賦值時,就會發生鎖存行為。最常見的兩種情況是:
1.決策語句分配給每個分支中的不同變量,如下面的代碼段所示,
2.決策語句不會對決策表達式的每個可能值執行分支。下面的代碼片段說明了這個問題。
在仿真中,這個簡單的例子似乎正確地仿真組合邏輯加法器、減法器和乘法器。但是,如果操作碼輸入的值應為2’b11,則本例不會對result變量進行任何賦值。因為result是一個變量,所以它會保留其以前的值,保留值的行為就像鎖存器一樣,盡管其目的是讓always_comb程序表現為組合邏輯。
即使使用always_comb程序,也會推斷出鎖存器。然而,綜合編譯器和lint checker將報告一個警告或非致命錯誤,即在always_comb程序中推斷出了鎖存器。此警告是always_comb優于常規always程序的幾個優點之一。always-comb程序記錄了設計工程師的意圖,當程序中的代碼與該意圖不一致時,軟件工具可以報告這一不匹配意圖。
審核編輯:郭婷
-
編程
+關注
關注
88文章
3592瀏覽量
93596 -
鎖存器
+關注
關注
8文章
904瀏覽量
41444 -
RTL
+關注
關注
1文章
385瀏覽量
59701 -
編譯器
+關注
關注
1文章
1618瀏覽量
49051 -
and
+關注
關注
0文章
32瀏覽量
7242
原文標題:避免組合邏輯程序中的意外鎖存
文章出處:【微信號:Open_FPGA,微信公眾號:OpenFPGA】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論