“要養成良好的Verilog代碼風格,要先有硬件電路框圖之后再寫代碼的習慣,設計出良好的時序,這樣才能在FPGA開發或者ASIC設計中起到事半功倍的效果,否則會事倍功半。”
01、代碼規范
一、概述
1、always/assign/reg/wire
2、文件名與module名要一致,一個文件一個module
3、統一的復位方式,異步復位上升沿有效(無論軟復位或硬復位)
4、盡量避免用低電平有效的信號,盡量高電平有效
5、狀態機一定要采用三段式
6、端口聲明輸入輸出要分開,最好要有區分輸入輸出的標示
7、條件分支要寫全。Case及if else等
8、信號名不要過長,不要超過32個字母
9、所有寄存器都要復位且有初始值
10、不允許使用門控時鐘或門控的復位
11、組合邏輯阻塞賦值,時序邏輯非阻塞賦值
12、內部信號避免出現三態
13、避免出現latch
14、多使用parameter,增加修改的便利性
15、連接同一端口的同一組信號盡量有公共的符號表示,如dav/sop/eop等
另外:
不允許將多個寄存器寫到一個always里面;
要為每一個寄存器單獨寫一個always,哪怕兩個信號很相關;
要有寫電路的意識,不能是寫軟件的風格(代碼短);
按照橫向思維,每個信號都要仔細考慮,考慮全。
剛開始時盡量避免同一個寄存器在多個模塊里面都賦值(Multi Driver);
代碼 - > 電路,寫的時候一定明白什么樣的代碼產生什么樣的電路;
設計流程:
設計目標分析 - > 功能模塊劃分 - > 確定關鍵電路時序和模塊間時序 - > 具體電路設計
設計電路尤其是數字電路,最關鍵的一環是:設計各模塊間的接口時序。這個工作必須在具體電路設計之前確定下來。
綜合的TOP_DOWN流程是對整個芯片加約束;而綜合的BOTTOM_UP流程是先把小模塊做綜合,然后把綜合好的模塊用一個頂層的模塊包進去,再綜合一次。電路較大時,用BOTTOM_UP流程。
時序是事先設計出來的,而不是事后測出來的,更不是湊出來的!
二、初學者注意的問題
對初學者一定要反復提醒自己注意:
1、避免把寫軟件的思想帶入到寫硬件電路中,對于verilog代碼而言,常常是簡單冗長的代碼出來的電路反而高效;
2、寫硬件電路代碼的時候頭腦中要有硬件結構,一定要弄明白什么樣的代碼能夠綜合出來什么樣的電路。
3、要養成簡單高效的寫代碼風格,寫電路設計的硬件代碼,關鍵的行為描述部分只允許用assing、always、if語句、case語句,其余的循環和函數之類的代碼都不提倡使用。
一個典型的verilog模塊的組成包括module,端口聲明,輸入輸出定義,輸出屬性的聲明,主要代碼及endmodule。都有具體的格式要求,可查找資料查看詳細的具體格式。另外,module的前面還有一個timescale及include和宏定義,端口聲明之后還有一些參數定義等。
需要提示的規范的module寫法是一個.v文件里只寫一個module。這里面最重要的是主要代碼部分,只需要掌握always、assign、wire、reg即可,assign語句后面盡量不要出現較為復雜的邏輯運算,復雜的邏輯運算需要修改成always的寫法,以提高可讀性。
數據的寫法要注意規范性,每種類型的數據都要注明位寬及類型。
在芯片設計中,memory類型的數組變量一般用在深度小于64的寄存器堆定義中,對于FPGA中不涉及,都是用軟件自動生成的RAM。不能對數組類型的變量中單獨的幾個bit進行操作,都是按照以“字”為單位進行操作。
運算符及表達式只需要注意區分單目和雙目的運算符即可,簡單來講,單目的一般是用來進行計算的運算符,常常用來進行邏輯運算,寫在賦值語句里面;而雙目的運算符常常用來進行關系的判斷,常常用在if語句的判斷條件里面。需要注意的是,運算符是有優先級的,為了代碼規范性及正確性,常常需要添加括號和空格進行隔離和區分。
對于語句而言,只允許用較為簡單的assign賦值語句和always語句。在電路設計的可綜合代碼中,不提倡使用for、while等軟件常用循環語句。always模塊中敏感變量列表中有沿觸發邏輯的是時序邏輯模塊,綜合出來的電路帶有DFF,在賦值的時候要用非阻塞賦值;always模塊中敏感變量列表中沒有沿觸發邏輯的是組合邏輯模塊,綜合出來的電路都是組合電路門的連接,在賦值的時候要用阻塞語句賦值。
if語句是有優先級的,同時滿足多個分支的情況下優先執行最前面的分支,case語句是沒有優先級的,可以同時執行多個滿足條件的分支。if語句嵌套最多不能超過兩級,否則會影響綜合出來電路的性能。if語句要寫全,一定要有else語句,并且組合邏輯中的else語句不能寫自己等于自己,否則就會形成組合邏輯的反饋環,對電路產生很大的隱患。另外,if語句的條件判斷語句不能過于冗長,如果條件判斷太復雜,也會影響電路的性能,最好把時序邏輯里面較為冗長的判斷邏輯單獨拉出去寫成組合邏輯,這樣就可以提高電路的性能。
經常采用initial語句來寫testbench.整個工程的宏定義可以寫成一個文件,在每個文件的module前面include上,這樣便于修改。
對于門級電路的描述也很重要,這常常是寫出關鍵路徑高效電路的一種最直接的方法。比如乘法器有很多種,如果用工具自動產生的電路,經常是不能滿足性能需求,這個時候可以自己采用門級的描述方式來寫booth編碼的乘法器等來替換代碼中的一個乘號,這樣才能提高電路的性能。
三、工程實例
一個FPGA工程應該把電路設計代碼和仿真代碼分開成hdl文件夾和sim文件夾兩個文件夾來存放,每個文件夾下都存放相應的文件,這樣可以便于高效管理。詳細例子可以參考從opencores網站上下載的工程。基本都是按照這樣的思路來進行的存儲。
四、代碼的review
代碼的review很重要,可以及早的發現問題,避免在后續調試階段發現定位問題耗費更多的時間和精力。
02、基本技能
1、采沿
上升沿、下降沿。
適用于根據一些信號進行計數,比如多少個emac幀等,若根據某些信號來計數,無法保證這些信號是否持續一個時鐘周期,所以需要進行取沿的操作。采沿時打一拍后,適用assign語句產生。
上升沿采樣
下降沿采樣
上升沿和下降沿采樣
沿檢測代碼:
reg reg_ff1,reg_ff2; always@(posedge clk ) begin reg_ff1 <= reg_in; reg_ff2 <= reg_ff1; end
上升沿:if((reg_ff1) & (!reg_ff2 ) )
下降沿if(( ! reg_ff1) & (reg_ff2 ) )
雙沿:if(reg_ff1 != reg_ff2)
2、“打拍”同步。
不同時鐘域的信號進行交互時,需要進行“打兩拍”的同步操作之后才能使用。主要是為了消除亞穩態問題。
具體代碼如下:
reg bdat1,bdat2; always@(posedge clkb ) begin bdat1 <= adat; bdat2 <= bdat1; end
3、同步復位與異步復位
(1)同步復位,綜合出來不帶復位端,代碼如下:
always @ (posedge clk) begin if (reset) q<= 1’b0 else q<= d; end
(2)異步復位,綜合出來帶復位端,代碼如下:
always @ (posedge clk or posedge reset) begin if (reset) q<= 1’b0 else q<= d; end
4、三段式狀態機
有限狀態機(FSM)的寫法,時序邏輯和組合邏輯分成兩個模塊寫。決不允許把輸出也寫在里面。
時序部分:只能有當前信號和下一狀態;
組合部分:組合內不能有輸出,即任何輸出都要經過寄存器才能輸出;
module state4 (clock,reset,out); input reset, clock; output [1:0] out; parameter [1:0] stateA=2’b00; parameter [1:0] stateB=2’b01; parameter [1:0] stateC=2’b10; parameter [1:0] stateD=2’b11; reg [1:0] state, nextstate, out; //第一段,時序邏輯部分 always @ (posedge clock) begin if (reset ==1,0’b0) state <= stateA; else state <= nextstate; end //第二段,組合邏輯部分 always @ (state) begin case (state) stateA: nextstate = stateB; stateB: nextstate = stateC; stateC: nextstate = stateD; stateD: nextstate = stateA; endcase end //第三段,輸出信號賦值部分,可能有多個always always@(postdge clock or negedge reset) begin if (reset==1’b0) out <= 2’b0; else … end endmodule
5、“One-hot” 編碼
one-hot編碼方式只用一個bit來表示一個狀態,這大大縮小了狀態譯碼的組合電路規模,使得路徑延時更小,因此狀態機的時鐘可以運行在更高的頻率上。
特例:不妨想象該狀態機就是一個循環計數器,如果采用binary編碼,則該計數器存在明顯的組合電路;而如果采用one-hot編碼,該計數器的綜合結果就是一個移位寄存器序列,根本不存在任何組合門!
6、if條件判斷不能過于復雜,若比較復雜,最好重新定義一個信號,用組合邏輯實現后再判斷,否則將影響性能。
7、乒乓操作。
乒乓操作最忌諱兩塊RAM的區分信號向無限遠處傳播,導致跟很多模塊糾纏,最終造成乒乓不起來。 因此,乒乓操作的一些RAM區分信號最好限制在模塊的內部,對外不可見。這樣才能準確的進行乒乓。
8、64Byte為存儲單元存儲問題
根據EMAC幀的幀長特點,選擇64Byte作為以太網幀存儲的基本單元,在進行流量等測試時測試幀長對吞吐率的影響會降至最小。
所用知識:C語言中隊列管理,鏈表等。
了解隊列管理模塊、內存分配模塊的基本功能。
9、RAM讀出是否寄存問題
整個設計中用到RAM的地方若采用工具生產,最好要統一采用讀出后寄存一拍再輸出的RAM。
10、仿真環境-BFM模型
需要掌握以太網PHY模型、簡單CPU模型(能夠處理中斷及配置寄存器功能)等簡單行為模型的編寫。此處不要求代碼規范。
11、看時序圖
會根據時序圖,尤其是一些總線關系,如地址、數據及讀寫使能之間的相互關系,模擬出相應的Master或者Slaver應該滿足的關系。
一種典型的應用是FPGA工具自動生成的FIFO或者RAM的時序圖能夠看明白,另外,一些較為常見的總線時序應牢記,如AMBA AHB總線。
12、了解腳本的含義
掌握簡單的Tcl、Perl等語言的基本操作。如Modelism不用圖形界面,而用命令行方式操作。
13、掌握仿真環境產生的方式
會使用Verilog語言熟練對文本進行操作。如從文件中讀出若干個以太網幀作為激勵,輸出端的結果寫成文件與正確結果文件進行對比。
14、掌握多種文本編輯工具
Ultra-Edit、Notepad++、GVIM等。會使用列操作等進行編輯,會使用BeyondCompare對文件夾或文件進行比較。
15、掌握版本管理工具的使用方法
會使用SVN等簡單的版本管理工具。會服務器端及客戶端的基本配置,會對代碼進行更新、下載不同的版本、log信息上傳等。養成良好的代碼版本管理習慣。
16、掌握Debussy等工具的使用
能夠看懂簡單的Debussy跟Modelsim仿真結合的腳本語言的含義。會對代碼中某些信號進行跟蹤,會從波形定位到代碼進行錯誤的檢查等。
17、掌握nLint工具的使用
導入代碼到工具中,能夠自助設計規則對所寫代碼進行代碼規范檢查,并明白常見的多驅動、賦值錯誤、敏感變量不全等常見的錯誤修改。
養成寫好代碼就用nLint進行檢查的良好習慣,尤其是對設計中原來以為要用到結果沒有用到的一些變量甚至邏輯代碼進行刪除,避免最后造成資源的浪費。
如自己感覺這些工具使用起來麻煩,則可以自己手動寫一個基于文本處理的代碼規范檢查腳本。
18、掌握SMART BITS等工具的使用
會以一定的速率產生自定義的以太網幀。能夠結合SMART BITS及FPGA板能夠完成回環實驗。
掌握Wireshark等相應功能常見軟件的使用方法,以便在沒有硬件設備的情況下也可進行FPGA調試。
19、掌握Quartus/ISE等工具的使用
會對設計代碼進行綜合、布局布線。
會生產或利用工具生產RAM、FIFO、PLL等IP。
會利用工具進行管腳分配。
編輯:hfy
-
FPGA
+關注
關注
1630文章
21783瀏覽量
605022 -
asic
+關注
關注
34文章
1205瀏覽量
120634 -
Verilog
+關注
關注
28文章
1351瀏覽量
110234
發布評論請先 登錄
相關推薦
評論