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