在學習Python時,作者有一句話對我影響很大。作者希望我們在學習編寫程序的時候注意一些業內約定的規范。在內行人眼中,你的編寫格式,就已經暴露了你的程度。學習verilog也是一樣的道理,一段好的verilog代碼,在完成設計要求的前提下,還需要條理清晰,有對應的注解,對非作者而言應該是友好的。因為對數字IC設計也處於初級階段,前期所寫的基本是在搜集資料的基礎上,添加一部分個人的理解,希望通過自己的不斷學習,沉淀出自己獨到的見解。
對於Verilog編寫規范,網上的資料比較散,其中較好的我覺得是2001版華為的編寫規范。下面簡稱規范(https://wenku.baidu.com/view/bbad6339fe00bed5b9f3f90f76c66137ee064fc8.html)百度文庫
我將在次規范的基礎上加入一些補充:
1.低電平有效信號,信號后加‘_n’。
2.模塊名小寫。
3.module例化名用U_xx_x表示(多次例化用次序號0.1.2...)。
4.使用降序排列定義向量有效位順序,最低位為0。
5.采用小寫字母定義reg,wire和input/output/inout。
6.采用大寫字母定義參數,參數名小於20個字母。
7.時鍾信號應前綴‘clk’,復位信號應前綴‘rst’。
8.三態輸出寄存器信號應后綴‘_z’。
9.代碼中不能使用VHDL保留字,更不能使用Verilog保留字。 ps:具體有哪些保留字可以百度搜索,這里不列舉。
10.輸出信號必須被寄存(只對頂層模塊)。ps:在查閱的各種資料中,都有提及這一點。
11.三態邏輯可以在頂層模塊中使用,子模塊中避免使用三態。
12.沒有未連接的端口。
13.到其他模塊的接口信號,按如下順序定義端口信號:輸入,(雙向),輸出。
14.建議使用coregen生成乘法電路。
15.采用基於名字的調用,而非基於順序的調用。
16.不要書寫空的模塊,即用一個模塊至少要有一個輸入和一個輸出。
17.時鍾事件的表達要用‘negedge<clk_name>’ 或 'posedge<clk_name>'的形式。
18.異步復位,高電平用‘if(<rst_name> == 1'b1)’,低電平有效用‘if(<rst_name> == 1'b0)’。 ps:if 內的判斷條件位寬為1。
19.if語句不能嵌套太多。
20.建議不使用include語句。
21.建議每個模塊加timescale。
22.代碼中給出必要的注釋。
23.每個文件有一個文件頭。ps:我的理解是每個文件最開頭應用注釋好,所寫模塊的名字、功能、版本、時間等。
24.每個文件只包含一個模塊。
25.模塊名與文件名保持一致。
26.同步時序邏輯的always block中有且只有一個時鍾信號,並且在同一個沿動作(如上升沿)。
27.同步時序邏輯的module中,在時鍾信號的同一個沿動作。
28.采用同步設計,避免使用異步邏輯(全局信號復位除外)。
29.一般不要將時鍾信號作為數據的信號輸入。
30.不要在時鍾路徑上添加任何的buffer。
31.不要門控時鍾。ps:
32.在頂層模塊中,時鍾信號必須可見。
33.不要采用向量的方式定義一組時鍾信號。
34.不要在模塊內部生成時鍾信號,使用DLL/PLL產生的時鍾信號。
35.建議使用單一的全局同步復位電路或者單一的全部異步復位電路。
36.不要在復位路徑上添加任何的buffer,也不要使用任何門控復位信號。ps:復位路徑上添加buffer,會使得復位信號到觸發器復位接收端口產生延遲,skew的產生,可能無法滿足復位恢復時間,從而導致亞穩態的產生。 門控會使得復位信號產生毛刺,增加亞穩態發生的可能性。
37.不使用PLI函數。
38.不使用事件變量。
39.不使用系統函數。
40.建議不使用任務。
41.不使用用戶自定義單元(UDP)。
42.不使用===,!==等不可綜合運算符。
ps: 補充Verilog不可綜合語句。
initial(只在testbench中使用)、events(在同步testbench時更有用)、real time、assign和deassign(reg型無法綜合,但是wire型可以)、fork join、primitives(只支持門級原語綜合)、table、敏感列表中同時帶有posedge和negedge(如always@(posedge clk or negedge clk)begin end 這個無法綜合)、同一個reg被多個always塊驅動、延時 #time ,比如a = #5 b ,此處仿真時候是可以的,但是在綜合時會自動忽略掉#time,相當於a = b、X或Z(未知態和高阻態),在條件表達式中不要使用它們,確保可以綜合。
43.不使用disable語句。
44.建議不使用forever,repeat,while循環語句。
45.避免產生latch(除CPU接口)。 ps:在if語句或者case語句中的所有條件分支中都有對變量有明確的賦值,不然會綜合出latch。
46.組合邏輯語句塊敏感列表中敏感變量必須和該模塊中使用的相一致,不能多也不能少。
47.在一個always語句中,有且僅有一個事件列表。
48.在時序always塊的敏感事件列表中,必須都是沿觸發事件,不允許出現電平觸發事件。
49.數據位寬要相匹配。
50.不使用real,time,realtime類型。
51.建議不使用integer類型。
52.位移變量必須是一個常數。
53.避免使用異步反饋電路。
54.時序邏輯語句塊中統一使用非阻塞型賦值。
55.組合邏輯語句塊使用阻塞型賦值。 ps:對於54 55需要了解一下阻塞和非阻塞的區別。 非阻塞賦值語句,右端表達式計算完並不會立刻傳遞給左端,而是等待下一個事件觸發前一刻再傳遞給左端,且它們是並行的。就是說,在所有的右端表達式在時鍾有效沿到來之時開始計算,等到下一個時鍾有效沿到來之前一刻,將值同時賦值給了左端。可以想象出它對時鍾沿觸發描述的恰到好處,所以用在時序邏輯中。 阻塞賦值語句,在每個右端表達式計算完之后,立刻傳遞給左端,並且后面的式子只能在前面完成后,方可運行。所以說是一個串行過程,而組合邏輯恰恰需要這樣的一個表達方式。
56.非阻塞賦值語句不加單位延時,尤其是對於寄存器類型的變量賦值時。
57.整型常量基數格式中不能有‘?’。
58.字符串中不能包含有控制字符(如CTRL鏈)。
59.禁止使用空的時序電路塊以及非法的always結構。
60.不要在連續賦值語句中引入驅動強度和延時。
61.不要為net,n_input,n_output,enable_gate型變量定義驅動強度,電荷保持強度以及延時。
62.禁止使用trireg(具有電荷保持特性的連接)NET型定義。
63.禁止使用tri0,tri1,triand和trior型連接。
64.在RTL級代碼中不能包含有initial結構,也不能對任何信號進行初始化賦值,應該采用復位的方式進行初始化。
65.不要在過程語句中使用assign,deassign,force,release等語句。
66.不要使用wait語句。
67.不要使用fork join語句塊。
68.不要為驅動類型為supply0和supply1型的連線(net)賦值。
69.設計中不使用macro_module。
70不要在RTL代碼中實例門級單元,尤其是下列單元:CMOS開關,RCMOS開關,NMOS開關,PMOS開關,RNOMS開關,RPMOS開關,trans雙向開關,rtrans雙向開關,tranif0,tranif1,rtranif0,rtranif1,pull_gate。
71.不要使用specify模塊。
這些規則中有一些我還沒有弄清楚,等到更多的實際應用中出現的時候,應該會有一種恍然大悟的感覺,實踐才是檢驗真理的唯一標准。