Verilog設計的可綜合性與問題分析


前言


用Verilog HDL編寫的設計模塊最終要生成實際工作的電路,因此,設計模塊的語法和編寫代碼風格會對后期電路產生影響,所以,若要編寫可實現的設計模塊,就需要注意一些問題


可綜合語法


可綜合的設計是最終實現電路所必需的,所以弄清哪些語法是可綜合的,哪些語法是不可綜合的非常有必要,而且設計者也必須知道一個代碼能否被綜合成最終電路;

例如:寫一個簡單的除法a/b,想妄圖直接通過綜合工具生成一個除法器是不現實的,還有有符號數和浮點數的時候也需要注意。

總之,設計者的思路定要從軟件角度轉變到硬件角度,很多在軟件中可以直接使用的情況到了硬件電路就需要從很底層的角度來編寫。

可綜合的語句有:

1)module 與 endmodule 模塊聲明的關鍵字
2)輸入input,輸出output和雙向端口inout的聲明
3)變量類型reg,wire,integer
4)參數parameter和宏定義define
5)所有的Verilog HDL內建門,如:add,or之類的門
6)數據流語句assign語句
7)行為級中敏感列表支持電平和邊沿變化,類似posedge,negedge
8)always,function可以被綜合,task中如果不含延遲可以被綜合
9)順序塊begin……end可以被綜合
10)if和 case語句可以被綜合

不可被綜合的語句


在Verilog HDL中不可被綜合的語法這里也簡單列出來:

(1)初始化initial結構不能被綜合,電路中不會存在這樣的單元。電路中一旦通電就會自動獲得初始值,除此之外時序電路可以用復位端完成初始化組合,電路不需要初始化
(2)#帶來的延遲不可被綜合。電路中同樣也不會存在這樣簡單的延遲電路,所有的延遲都要通過計時電路或交互信號來完成
(3)並行塊fork…join不可被綜合,並行塊的語義在電路中不能被轉化
(4)用戶自定義原語UP不可被綜合
(5)時間變量time和實數變量real不能被綜合
(6) wait ,event , repeat ,forever等行為級語法不可被綜合
(7)一部分操作符可能不會被綜合,例如,除法/操作和求余數%操作
  • 補充:
    綜合工具也在不斷更新和加強,有些現在不能被綜合的語法慢慢地會變得可以綜合,像比較簡單的initial結構在一些 FPGA工具中也可以被識別,同時能被轉化為電路形式
    而有些語句是由於語法特點被綜合工具限制,比較典型的就是for語句。
    for循環語句簡潔明了,編寫代碼非常方便,但在綜合過程中會被完全展開,如 for(i=0;1<9; i=i+1)這條語句在綜合工具中就會被展開成10個語句並形成10個相似的電路,這些電路都會出現在最終的電路圖里,造成電路規模展開過大。而且for循環中的i一般都比較大,這樣展開的效果就更加明顯。
    但使用for的時候設計者的思路其實是想要通過一個簡單的電路完成判斷,然后執行 for所包含的語句,這樣設計者和綜合工具之間的處理過程不一樣,只能以綜合工具為准。

  • 注意:
    不可綜合的語句在仿真工具中是編譯不出來的
    因為仿真工具只能檢查仿真相關的語法,不能考慮后期綜合電路的情況,而仿真所用的測試模塊沒有語法限制,所以無法提供可綜合語法的幫助。


Verilog代碼風格


阻塞與非阻塞


使用的賦值類型依賴於所描述的邏輯類型:

  • 時序塊RTL代碼中使用非阻塞賦值,非阻塞賦值保存值直到時間片段的結束,從而避免仿真時的競爭情況或結果的不確定性;
  • 組合的RTL代碼中使用阻塞賦值,阻塞賦值立即執行
  • 當用always塊為組合邏輯建模,使用“阻塞賦值”;
  • 當在同一個always塊里面既為組合邏輯又為時序邏輯建模,使用“非阻塞賦值”;
  • 不要在同一個 always 塊里面混合使用“阻塞賦值”和“非阻塞賦值”

多重驅動問題


多重驅動問題是初學者最容易犯的錯誤之一,主要原因就是邏輯划分不清

在可綜合的模塊中,一個信號的賦值只發生在一個always結構中,如果出現在兩個always 結構中就構成了多重驅動,綜合工具會認為這兩個電路會嘗試對同一個變量賦值,實際效果就會造成電路信號的碰撞,然后生成無法預料的結果。

所以設計者在設計模塊的時候一般都會在一個always結構中把某個輸出的所有情況都寫清楚,確保沒有考慮不全的情況,然后再去編寫其他輸出的情況。

多重驅動問題一般發生在有多個判斷條件的情況時,此時的設計思路不要考慮“在這些情況下設計模塊的輸出都應該是什么”,而是要考慮“每個輸出在這些情況下都應該輸出什么”,也就是不要從情況人手,而要從輸出的角度來看待電路

而在Verilog HDI編寫設計模塊的語法指導中也建議設計者每個always結構完成一個信號的賦值,除非幾個信號產生變化的情況都相同或者信號之間有強烈的依賴關系時才放在一起。


敏感列表不完整


  • @引導的敏感列表中必須包含完整的敏感列表,這是針對組合邏輯電路而言的。
  • 時序電路中@的敏感事件只是clock的邊沿或reset一類信號的邊沿情況,若出現其他變量就會變成異步電路,而異步電路的設計很多綜合工具並不支持或支持得很差,需要人工幫助。

組合邏輯電路敏感列表不完備就會造成仿真結果不正確,以及最終實現的電路結構不正確或出現鎖存器結構。

例如:

always @(a)
c=a^~b;

這個代碼中希望生成的是同一個電路,但是敏感列表缺少b,
這樣b的變化不會促使always結構發生變化。
此代碼綜合后可能會生成一個帶控制端的鎖存器的電路形式,當然也可能是正確的,但設計者不能過分依賴綜合工具。

把敏感列表補充完整如下:
always @(a or b)
c=a^~b;

if-else不成對出現


例如:

reg [1:0]out;
always @(posedge clock)begin
  if(s==2'b00)out<=2'b00;
  if(s==2'b11)out<=2'b11;
end

存在的問題:

  • 代碼優先級問題

指兩個if先判斷哪一個?如果電路整體資源情況包括時序、面積等比較充裕,先執行哪個都可以,但如果電路資源情況比較緊張,這兩個if語句的先后就可能決定了時序上的成功和失敗。
因為這兩個if語句最后實現電路的情況完全由不同的綜合工具自已定義,最終電路不可確定。

  • if…else問題
    出現了一個 if,必然要出現與之對應的else,否則電路中就容易出現鎖存器
    鎖存器這種電路結構在非故意使用的情況下出現就是錯誤的,而else的不使用是造成鎖存器被綜合出來的原因之一

修改:

reg [1:0]out;
always @(posedge clock)begin
  if(s==2'b00)out<=2'b00;
  else if(s==2'b11)out<=2'b11;
  else out<=2'b11;
end

case中缺少default


在case語句中也容易出現鎖存器

例:

reg [1:0] sel;
  always @(sel,a,b)begin
    case(sel)
      2'b00:out = a + b;
      2'b01:out = a - b;
      2'b00:out = a + b;
      2'b00:out = a + b;
end

該case語句中缺少了default,效果和if語句中缺少case一樣,容易被綜合工具綜合成鎖存器,無論default情況是否存在都要添加這一項,而且不要對其賦值為x,類似於:default: out= 2' bxx;

這樣在仿真過程中是可以的,運行時比較類似電路剛啟動所處的未知狀態,但實際綜合過程中x值是被忽略的,所以要給出一個明確的賦值。

如果設計者不知道應該在default中產生什么輸出值,或者在else中產生什么輸出值,也可以僅添加一個default而不添加任何語句,如下:default:;


組合與時序混合設計


栗子:

reg x, y, Z;
always @(x, y,z, posedge reset)begin //時序
  if(reset)
    out = 0;   //時序
  else 
    out = x ^ y ^ Z; //組合
end

一方面希望完成異或,另一方面又希望能在一個always結果中完成清零過程,得到一個混合設計模塊。

從根本上將二者划分開是最好的解決途徑:

reg x,y,Z;
always @(posedge reset)begin
  if(reset)begin
    x<=0;
    y<=0;
    z<=0;
  end
  else …
end
assign out =x^y^z;

在建立可綜合模型時,能使用數據流語句實現組合邏輯電路時應盡量使用數據流描述建模,而不要使用行為級的阻塞賦值,因為assign語句層次較低,綜合轉化不容易發生歧義,所寫語句與最后實現電路一致性較高。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM