眾所周知,用于FPGA開(kāi)發(fā)的硬件描述語(yǔ)言(HDL)主要有兩種:Verilog和VHDL,VHDL的出現(xiàn)時(shí)間要比Verilog早,Verilog由于其簡(jiǎn)單的語(yǔ)法,和C語(yǔ)言的相似性,目前被各大公司廣泛使用。
其實(shí)我大學(xué)時(shí)學(xué)習(xí)的是VHDL語(yǔ)言,后來(lái)由于公司都是使用的Verilog,又重新學(xué)習(xí)了Verilog,好在有C語(yǔ)言基礎(chǔ),Verilog很快就上手了。
Verilog標(biāo)準(zhǔn)文檔主要有3個(gè)版本,分別是:
Verilog-1995
Verilog-2001
Verilog-2005
都是由IEEE頒布。目前最新的Verilog標(biāo)準(zhǔn)是2005版,相比于前兩個(gè)版本,2005更簡(jiǎn)潔,更靈活。
雖然一些官方的代碼,如Xilinx一些IP核代碼,為了兼容以前的綜合工具,還是基于Verilog-2001標(biāo)準(zhǔn),但我還是強(qiáng)烈建議你使用最新的Verilog-2005標(biāo)準(zhǔn)。
IEEE-2005
所以,本文都是基于IEEE-2005語(yǔ)法標(biāo)準(zhǔn),即《IEEE P1364-2005/D3:Draft Standard for Verilog HardwareDescription Language》官方標(biāo)準(zhǔn)文檔。
良好的代碼規(guī)范可以提高代碼的可讀性、可復(fù)用性、簡(jiǎn)潔清晰,這也是一種職業(yè)素質(zhì)的體現(xiàn)。
我們的目標(biāo)是:
封面
都有哪些內(nèi)容?
命名
文件命名
端口命名
變量命名
參數(shù)命名
結(jié)構(gòu)
整體結(jié)構(gòu)
端口聲明
空格和縮進(jìn)讓代碼更清晰
小括號(hào)增加可讀性
例化
注釋
其他
IEEE-2005標(biāo)準(zhǔn)下載
命名
命名主要包括文件和模塊命名,端口命名,變量命名,參數(shù)命名等,概括來(lái)說(shuō)就是:有意義,簡(jiǎn)短易讀,重要的是不要使用拼音!
文件命名
文件名和模塊名保持一致,一個(gè)文件只寫(xiě)一個(gè)模塊。
文件命名 文件命名要有含義,且簡(jiǎn)短易讀,文件名統(tǒng)一使用小寫(xiě)字母,并使用下劃線分割文件名。
底層驅(qū)動(dòng)類模塊命名,使用drv_xxx類型,如:drv_led.v,drv_i2c.v,drv_ad7606.v
串口發(fā)送一字節(jié):uart_tx_byte.v
異步和同步FIFO,并指示深度和寬度:fifo_async_512_16.v和fifo_sync_256_64.v
TestBench文件名問(wèn)源文件名后加_tb,如源文件drv_led.v,則對(duì)應(yīng)的testbench文件命名為drv_led_tb.v
頂層模塊統(tǒng)一命名為top.v,或top_project_name.v,如EEPROM讀寫(xiě)示例工程頂層命名為top_eeprom_demo.v
端口命名
端口命名和文件命名一樣,統(tǒng)一使用小寫(xiě)字母,并使用下劃線進(jìn)行分割。
如果是頂層模塊,而且是連接到實(shí)際的FPGA管腳,后加_pad_i,_pad_o,_pad_io來(lái)命名,表示連接到實(shí)際的FPGA硬件管腳上。
頂層端口命名
變量命名
時(shí)鐘信號(hào)統(tǒng)一使用clk命名,如果是特定時(shí)鐘頻率,可以在后面添加時(shí)鐘頻率,如clk_50m
復(fù)位信號(hào)統(tǒng)一使用rst命名,如果是低電平有效,后加_n表示,如rst_n
標(biāo)志位命名:flag_rise/flag_fall/flag_clr
寄存器打拍信號(hào)命名添加_reg:reg rxd_reg
移位寄存器命名添加后綴_sreg:reg [3:0] busy_sreg
部分通用的縮寫(xiě):
縮寫(xiě) | 全拼 | 含義 |
---|---|---|
rst | reset | 復(fù)位 |
clk | cloc | 時(shí)鐘 |
rd | read | 讀取 |
wr | write | 寫(xiě)入 |
addr | address | 地址 |
ack | acknowledge | 響應(yīng) |
參數(shù)命名
Verilog中的參數(shù)類似于C語(yǔ)言中的define,主要有以下兩類localparam和parameter,兩者的區(qū)別是前者不可以在例化時(shí)進(jìn)行參數(shù)傳遞,而后者可以在例化時(shí)進(jìn)行參數(shù)傳遞。
其他的變量,文件名都是統(tǒng)一小寫(xiě),只有參數(shù)定義有全部大寫(xiě)的待遇,當(dāng)需要定義一些常量時(shí),可以通過(guò)參數(shù)聲明指定一個(gè)有意義的名稱。如:
parameterLED_ON=1'b0; parameterLED_OFF=!LED_ON; parameterBAUD_RATE=115200; parameterTIME_100MS=25_000_000;
狀態(tài)機(jī)的狀態(tài)通常使用localparam來(lái)定義,并指定有意義的名稱,統(tǒng)一使用Sn_NAME的格式,并指定位寬。如:
localparamS0_IDLE=4'd0; localparamS1_START=4'd1; localparamS2_DOING=4'd2; localparamS3_END=4'd3; localparamS_FINISH=4'd4; localparamS_ERROR='d5;//autoadaptive
結(jié)構(gòu)
整體結(jié)構(gòu)
建議Verilog模塊文件按照如下結(jié)構(gòu)進(jìn)行書(shū)寫(xiě)。
/*1.文件頭:說(shuō)明版權(quán)信息,文件功能,作者,版本歷史等*/ /*2.端口聲明:input/output/inout*/ /*3.宏定義:`define*/ /*4.參數(shù)定義:localparam/parameter*/ /*5.寄存器定義:reg*/ /*6.線網(wǎng)類型定義:wire*/ /*7.互聯(lián)定義:assign*/ /*8.時(shí)序邏輯描述:always*/
示例:
/*1.filehead*/ /*********************************************************** Copyright2021'wechat:mcu149'.Allrightsreserved. FileName:drv_led.v Function:leddriver Author:mcu149 SVN: SVNRevision:1490 SVNDate:2021-06-051949 Revision: 2020-09-09:Rev1.0 2020-10-01:Rev1.1 ************************************************************/ /*2.input/output/inout*/ moduledrv_led( //Inputs inputrst_n, inputclk_50m, inputen, //Outputs outputled1, outputregled2=0//defineinitialvalueis0 ); /*3.define*/ /*4.parameter/localparam*/ parameterTIME_500MS=32'd25_000_000; /*5.reg*/ reg[31:0]cnt=0; /*6.wire*/ wireflag_toggle=(cnt==TIME_500MS); /*7.assign*/ assignled1=(en==0)?0:cnt[20]; /*8.alwaysblock*/ always@(posedgeclk_50m)begin if(!rst_n) cnt<=?0; ????else?if(flag_toggle) ????????cnt?<=?0; ????else? ????????cnt?<=?cnt?+?1; end always?@?(posedge?clk_50m)?begin ????if(!rst_n) ????????led2?<=?0; ????else?if(!en)? ????????led2?<=?0; ????else?if(en)?begin ????????if(flag_toggle) ????????????led2?<=?!led2; ????end end endmodule
端口聲明
輸入端口放在一起,輸出端口放在一起,雙向端口放在一起。如果某個(gè)輸出信號(hào)需要確定初始值,可以在端口定義時(shí)直接進(jìn)行指定,這也是Verilog-2005新添加的功能。
端口命名
這一點(diǎn)有些朋友可能是按照功能進(jìn)行劃分,如連接同一芯片的放在一起。
輸入輸出分開(kāi)放的好處是,在例化時(shí)可以很方便的區(qū)分哪些是輸入哪些是輸出。
空格和縮進(jìn)讓代碼更清晰
運(yùn)算符兩端增加一個(gè)空格,可以讓程序結(jié)構(gòu)更清晰,可讀性更高
縮進(jìn)風(fēng)格采用KR風(fēng)格,即begin寫(xiě)在行尾,不占用單獨(dú)一行,end單獨(dú)占用一行
縮進(jìn)統(tǒng)一使用4個(gè)空格來(lái)代替TAB鍵
if/else等語(yǔ)句只有一行時(shí),可以省略begin-end
合理添加空行進(jìn)行塊區(qū)分,不同的always塊進(jìn)行換行隔開(kāi)
以下是兩種代碼的書(shū)寫(xiě)規(guī)范,合理縮進(jìn),合理增加空格大大增加了可讀性。
合理縮進(jìn)
小括號(hào)增加可讀性
在學(xué)校里有些考試題,為了考察學(xué)生對(duì)各種運(yùn)算符優(yōu)先級(jí)的掌握程度,出一些反人類的題目。
而做實(shí)際項(xiàng)目不像考試,追求的是可讀性和易用性,所以當(dāng)使用多個(gè)運(yùn)算符時(shí),為了增強(qiáng)可讀性,避免歧義,不要吝嗇使用小括號(hào)來(lái)表示運(yùn)算的優(yōu)先級(jí)。
運(yùn)算符優(yōu)先級(jí)
例化
例化可以認(rèn)為是FPGA開(kāi)發(fā)的靈魂所在了,例化的過(guò)程其實(shí)就是硬件模塊的調(diào)用過(guò)程,比如我們用Verilog描述了一個(gè)3-8譯碼器的模塊,可以在不同的地方去使用(例化)它,并分別命名為ut0/ut1/ut2等等,而且還可以在例化時(shí)指定參數(shù),如串口發(fā)送和接收模塊,通過(guò)指定不同的參數(shù)來(lái)實(shí)現(xiàn)不同波特率的兼容。
例化和端口聲明順序保持一致,輸入端口放在一起,輸出端口放在一起
多比特信號(hào),在例化時(shí)需要指定位寬,以增加可讀性
頂層模塊只進(jìn)行模塊例化,不寫(xiě)任何控制語(yǔ)句
示例:
wire[7:0]rx_data; wirerx_done; wirerx_err; /*串口接收1字節(jié)*/ uart_rx_byte#( .BAUD_RATE(32'd115200), .EN_PARITY(2'd0),//0:無(wú)校驗(yàn)位,1:奇校驗(yàn),2:偶校驗(yàn) .EN_STOP_2(1'b0)//1:使能2位停止位 )uart_rx_byte_0( //Inputs .clk(clk_32m), .rst_n(rst_n), .rxd(uart_rxd), //Outputs .data_rx(rx_data[7:0]),//指定位寬 .done(rx_done), .err(rx_err) );
注釋
不要相信什么代碼就是最好的注釋!我不否認(rèn)有些人的代碼寫(xiě)的就是很規(guī)范,命名合理,格式清晰。
但是我覺(jué)得你還沒(méi)有達(dá)到那種程度,不能保證每一個(gè)人都能讀懂沒(méi)有注釋的代碼。注釋不僅是為了給別人看,更多的也是為了給自己看,好記性不如爛筆頭。
注釋統(tǒng)一使用/**/注釋的方式,或者使用與//混合使用,看個(gè)人習(xí)慣!
每個(gè)變量定義后需要注釋變量的功能
每個(gè)always塊功能需要注釋
狀態(tài)機(jī)狀態(tài)含義需要注釋
條件語(yǔ)句的后面需要添加注釋
代碼修改,注釋也要隨之修改
其他
合理使用generate for可以批量化定義和例化模塊,減少代碼量,提高可讀性
testbench中使用task和function可以提高效率
移位操作替換為拼接補(bǔ)0操作,更易讀
時(shí)序邏輯統(tǒng)一使用非阻塞賦值,即<=符號(hào)
一行字符不要超過(guò)80個(gè),過(guò)長(zhǎng)通過(guò)換行來(lái)處理
先有頂層設(shè)計(jì),然后劃分子模塊功能,或者自底向上方法
模塊化設(shè)計(jì),提高模塊可復(fù)用程度
能用case的盡量不要用if/else
reg類型變量,根據(jù)需要看是否鎖存。
責(zé)任編輯:lq6
-
Verilog
+關(guān)注
關(guān)注
28文章
1365瀏覽量
111779 -
vhdl
+關(guān)注
關(guān)注
30文章
819瀏覽量
129551
原文標(biāo)題:如何寫(xiě)出易于維護(hù)的Verilog代碼?
文章出處:【微信號(hào):zhuyandz,微信公眾號(hào):FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
水利大壩安全監(jiān)測(cè)有哪幾個(gè)方面

評(píng)論