1.命名規(guī)則
用有意義而有效的名字
有效的命名有時(shí)并不是要求將功能描述出來(lái),如:
for(i =0;i 1024;i = i +?1) ? ?Mem[i] <= #1?32'b0; ? ??
用連貫的縮寫(xiě)
采用縮寫(xiě)時(shí)應(yīng)該主義同一信號(hào)在模塊中的一致性.如:
Addraddress Pntrpointer Clkclock Rstreset
用最右邊的字符下劃線代表低電平有效,高電平有效的信號(hào)不得以下劃線表示,短暫的有效信號(hào)建議采用高電平有效.如:
Rst_ Trdy_ Irdy_
大小寫(xiě)原則
名字一般首字符大寫(xiě),其余小寫(xiě)(但是parameter/integer定義的數(shù)值名可以全部大寫(xiě)),兩個(gè)單詞之間用下劃線連接.如:
Data_in Mem_wr Rd_req Sensor_ctrl
全局信號(hào)名中應(yīng)包含信號(hào)來(lái)源的信息.
如:D_addr[7:2],這里的"D"指明了地址是解碼模塊(Decoder module)的地址.
同一信號(hào)在不同層次應(yīng)保持一致性
自己定義的常數(shù)和類(lèi)型等用大寫(xiě)表示.如:
parameter CYCLE=100;
避免使用保留字
如:in,out,x,z等不能夠作為變量,端口或模塊名
添加有意義的后綴,使信號(hào)名更加明確,常用的后綴有:
_Clk 時(shí)鐘信號(hào) _next 寄存前的信號(hào) _z 連到三態(tài)輸出的信號(hào) _f 下降沿有效的寄存器 _xi 芯片原始輸入信號(hào) _xo 芯片原始輸出信號(hào) _xod 芯片的漏極開(kāi)路輸出 _xz 芯片的三態(tài)輸出 -xbio 芯片的雙向信號(hào)
2.Modules
頂層模塊應(yīng)知識(shí)內(nèi)部模塊間的互聯(lián)
Verilog設(shè)計(jì)一般都是層次性的設(shè)計(jì),也就是在設(shè)計(jì)中會(huì)出現(xiàn)一個(gè)或多個(gè)模塊,模塊間的調(diào)用在所難免.可把設(shè)計(jì)比喻成樹(shù),被調(diào)用的模塊就是輸液,沒(méi)被調(diào)用的模塊就是樹(shù)根,那么在這個(gè)樹(shù)根模塊中,除了內(nèi)部的互聯(lián)和模塊的調(diào)用外,盡量避免再做邏輯,如不能再出現(xiàn)對(duì)reg變量賦值等.這樣做的目的是為了更有效的綜合,因?yàn)樵陧攲幽KVS出現(xiàn)中間邏輯,Synopsys的Design Compiler就不能把子模塊中的邏輯綜合到最優(yōu).
每個(gè)模塊應(yīng)該在開(kāi)始處注明文件名,功能描述,引用模塊,設(shè)計(jì)者,設(shè)計(jì)時(shí)間,以及版權(quán)信息等.如:
/*==============================================================================================*/ Filename : RX_MUX.v Author : Dongyi Lin Description : Called by : Top module Revision History : 22-05-27 Revision : 1.0 Email : lindongyi@163.com Company : Hunan Institute of Advanced SensingandInformation Technology, Xiangtan Univeristy Copyright : 2022, Xiangtan University, All right reserved /*==============================================================================================*/
不要對(duì)Input進(jìn)行驅(qū)動(dòng),在module內(nèi)不要存在沒(méi)有驅(qū)動(dòng)的信號(hào),更不能在端口模塊出現(xiàn)沒(méi)有驅(qū)動(dòng)的輸出信號(hào),避免再仿真或綜合時(shí)產(chǎn)生warning,干擾錯(cuò)誤定位.
每行應(yīng)限制在80個(gè)字符以?xún)?nèi),以保持代碼的清晰,沒(méi)關(guān)和層次感.
一條語(yǔ)句占用一行,如果超過(guò)80個(gè)字符則要換行.
電路中調(diào)用的module名用Uxx表示.向量大小要表示清晰,采用基于名字的(name_based)調(diào)用,而非基于順序的(order_based).
Instance Uinstance2( .DataOut (DOUT ), .DataIn (DIN ), .Cs_ (Cs_), );
時(shí)鐘的上升沿或下降沿采樣信號(hào),不能一會(huì)上升沿,一會(huì)用下降沿.如果既要用上升沿又要用下降沿,應(yīng)該分成兩個(gè)模塊設(shè)計(jì).建議在頂層模塊中對(duì)Clock做一個(gè)not門(mén),
在層次模塊中如果要用時(shí)鐘下降沿就可以用not門(mén)產(chǎn)生的Posedge Clk_,這樣的好處是在整個(gè)設(shè)計(jì)中采用同一種時(shí)鐘出發(fā),有利于綜合.
在模塊中增加注釋.
對(duì)信號(hào),參量,引腳,模塊,函數(shù)及進(jìn)程等加以說(shuō)明,便于閱讀與維護(hù).
Module名稱(chēng)要用大寫(xiě)表示,且應(yīng)該與文件名保持一致.如:
module DFF_ADSYNC_RST( Reset, Clk, Data, Qout );
要嚴(yán)格芯片級(jí)模塊的劃分
只有頂層包括IO引腳(pads),中間層是時(shí)鐘產(chǎn)生模塊,JTAG,芯片的內(nèi)核(CORE),這樣便于對(duì)每個(gè)模塊加以約束仿真,對(duì)時(shí)鐘也可以仔細(xì)仿真.
模塊輸出寄存器化
對(duì)所有的模塊的數(shù)據(jù)加以寄存,使得輸出的驅(qū)動(dòng)強(qiáng)度和輸入的延遲可以預(yù)測(cè),從而使得模塊的綜合過(guò)程更簡(jiǎn)單.
3.Net and Register
一個(gè)reg變量只能在一個(gè)always語(yǔ)句中賦值
向量有效位順序一邊為從大到小
推薦Data[4:0]這種格式的定義.
對(duì)net和register類(lèi)型的數(shù)據(jù)要做聲明(在PORT中).
4.Expressions
用括號(hào)表示執(zhí)行的優(yōu)先級(jí),對(duì)讀者更情緒,更有意義,如:
if(alpha =delta)...就不如下面的更好 if((alpha =delta))
用函數(shù)(function)來(lái)代替表達(dá)式的多次重復(fù)
這樣在以后的版本升級(jí)時(shí)更便利,而且經(jīng)常使用的一組描述可以寫(xiě)到一個(gè)任務(wù)(task)中
5.IF語(yǔ)句
向量比較時(shí),比較的向量要相等
在向量比較時(shí),verilog將位數(shù)小的向量做0擴(kuò)展以使得他們的長(zhǎng)度相匹配,它的自動(dòng)擴(kuò)展是隱式的.建議采用顯式擴(kuò)展.如:
reg Abc[7:0]; reg Bca[3:0]; ...... if(Abc == {4'b0,Bca})begin ...... if(Abc ==8'b0)begin
每一個(gè)if都應(yīng)該有一個(gè)else與之對(duì)應(yīng)
沒(méi)有else可能會(huì)使得綜合出的邏輯和RTL級(jí)的邏輯不同,如果條件為假時(shí)不盡興任何操作,則使用一條空語(yǔ)句,如:
always@(Cond)begin if(Cond) DataOut <= DataIn; ? ? end ? ?//以上語(yǔ)句DataOut會(huì)綜合出鎖存器.
如果變量在if-else語(yǔ)句或case語(yǔ)句中沒(méi)有被完全賦值,則應(yīng)該提前給變量一個(gè)缺省值,即:
V1 =2'b00; V2 =2'b00; V3 =2'b00; //給V1,V2,V3缺省值,在后面賦值變量時(shí)有一個(gè)默認(rèn)值在 if(a == b)begin V1 =2'b01; V2 =2'b10; //V3isnotassigned, so thedefaultvalueofV3is2'b00; end elseif(a == c)begin V2 =2'b10; V3 =2'b11; //V1isnotassigned, so thedefaultvalueofV1is2'b00; end ...
6.case語(yǔ)句
case語(yǔ)句通常被綜合為一級(jí)多路復(fù)用器,而if-then-else語(yǔ)句則綜合為優(yōu)先編碼的串接的多個(gè)多路復(fù)用器.通常case語(yǔ)句比if語(yǔ)句快,有限編碼結(jié)果在信號(hào)到達(dá)時(shí)有先后.case語(yǔ)句仿真比條件語(yǔ)句快.
所有的case語(yǔ)句都應(yīng)該有一個(gè)default case,且允許空語(yǔ)句出現(xiàn)如:
default:;
7.Function
在function的最后給function賦值,如:
functionCompareVectors; input[199:0]Vector1; input[199:0]Vector2; input[31:0]Length; //local variables integeri; regEqual; begin i =0; Equal =1;//給Equal賦初值 while((i < Length)&& Equal)begin? ? ? ? ? ? ?if(Vector2[i] !==?1'bx)begin? ? ? ? ? ? ? ? ?if(Vector1[i] !== Vector2[i]) ? ? ? ? ? ? ? ? ? ?Equal =?0; ? ? ? ? ? ? ? ?else; ? ? ? ? ? ?end? ? ? ? ? ? ?i = i +?1; ? ? ? ?end? ? ? ? ?CompareVectors = Equal;?//賦值放在function的最后? ? ?endendfunction
在function中避免使用全局變量
否則容易引起HDL行為及仿真和門(mén)級(jí)仿真的差異.如:
functionByteCompare; input [15:0] Vector1; input [15:0] Vector2; input [7:0] Length; begin if(ByteSel)//ByteSel是全局變量,如果在其他位置無(wú)意修改了,可能導(dǎo)致函數(shù)結(jié)果錯(cuò)誤, //所以最好在端口加以定義 ... else ... end endfunction
注意,函數(shù)與任務(wù)的調(diào)用均為靜態(tài)調(diào)用.
8.Assignment
Verilog有兩種賦值方式:過(guò)程賦值(procedural)和連續(xù)賦值(continuous).過(guò)程復(fù)制用于過(guò)程代碼(initial,always,task,function)中給reg和integer變量,time ealtime eal復(fù)制,而連續(xù)賦值一般給wire變量賦值.
always@(敏感表),敏感表要完整,如果不完整,將會(huì)引起仿真和綜合結(jié)果不一致,如:
always@(dorClr) if(Clr) q =1'b0; elseif(e) q = d; //以上語(yǔ)句在行為及仿真時(shí)e的變化不會(huì)使仿真器進(jìn)入該always塊,導(dǎo)致仿真結(jié)果錯(cuò)誤.
assign/deassign僅用于仿真加速,僅對(duì)寄存器有用.
force/release僅用于debug,對(duì)寄存器和線網(wǎng)型都有用.
避免使用disable
對(duì)任何reg賦值,都用非阻塞賦值(<=)代替阻塞賦值(=),reg的非阻塞賦值要加單位延遲,但異步復(fù)位可加可不加.如:
always@(posedge Clk or negedge Rst_)begin if(!Rst_)begin Rega <=?0; ?//non_blocking assignment ? ? ? ? ? ? Regb <=?0; ? ? ? ?end? ? ? ? ?else?if(Soft_rst_all)begin? ? ? ? ? ? ?Rega <=?#u_dly ?0; ?//add unit delay? ? ? ? ? ? ?Regb <=?#u_dly ?0;? ? ? ? ?end? ? ? ? ?else?if(Load_init)begin? ? ? ? ? ? ?Rega <=?#u_dly ?init_rega;? ? ? ? ? ? ?Regb <=?#u_dly ?init_rega;? ? ? ? ?end? ? ? ? ?else?begin? ? ? ? ? ? ?Rega <=?#u_dly ?Rega << 1; ? ?? ? ? ? ? ? ?Rega <=?#u_dly ?St_1; ? ?? ? ? ? ?end? ? ?end?//end?Rega,Regb assignment
9.Combinatorial vs Sequential Logic
如果一個(gè)事件持續(xù)幾個(gè)時(shí)鐘周期,設(shè)計(jì)時(shí)就用時(shí)序邏輯代替組合邏輯. 如:
wireCt_24_e4; //Ct_24_e4 last over several clock cycles assign Ct_24_e4 = (count8bit[7:0] >=8'h24) & (count8bit[7:0] <=?8'he4);
這種設(shè)計(jì)將綜合處兩個(gè)8bit加法器,而且會(huì)產(chǎn)生毛刺,對(duì)于這種電路,要采用時(shí)序設(shè)計(jì),代碼如下:
regCt_24_e4; always@(posedgeClkornegedgeRst_)begin if(!Rst_) Ct_24_e4 <=?1'b0; ? ? ? ?else?if(count8bit[7:0] >8'he4) Ct_24_e4 <= #u_dly ?1'b0; ? ? ? ?else?if(count8bit[7:0] >8'h23) Ct_24_e4 <= #u_dly ?1'b1; ? ? ? ?else? ? ; ? ?end
內(nèi)部總線不要懸空.在default狀態(tài),要把他上拉或下拉.
wire OE_default; assign OE_default = !(oe1 | oe2 | oe3); assign bus[31:0] = oe1 ? Data1[31:0]: oe2 ? Data2[31:0]: oe3 ? Data3[31:0]: OE_default ?32'h0000_0000://如果bus不等于oe1,oe2,oe3中的任何一個(gè), //若等于OE_default,則bus為32'h0即拉低,否則拉高為高阻態(tài). 32'hzzzz_zzzz;
10.Macros 宏指令
為了保持代碼的可讀性常用`define做常數(shù)聲明
把`define放在一個(gè)獨(dú)立的文件中
參數(shù)(parameter)必須在一個(gè)模塊中定義,不要傳遞參數(shù)到模塊(仿真測(cè)試向量例外);
define可以在任何地方定義,要把所有的define定義在一個(gè)文件中(極少的一個(gè)兩個(gè)define就不用了吧),在編譯源代碼時(shí)首先把這個(gè)文件讀入.
如果希望宏的作用于僅在一個(gè)模塊中,就用參數(shù)來(lái)代替.
11.Comments
對(duì)更新的內(nèi)容要做注釋
在語(yǔ)法塊的結(jié)尾做標(biāo)記
每一個(gè)模塊都應(yīng)該在模塊開(kāi)始處做模塊級(jí)的注釋(參考前面的標(biāo)準(zhǔn)模塊頭)
在端口列表中出現(xiàn)的端口信號(hào),都應(yīng)該做簡(jiǎn)要的功能描述.
12.FSM 狀態(tài)機(jī)
狀態(tài)機(jī)的狀態(tài)分配
Verilog描述狀態(tài)機(jī)時(shí)必須有parameter分配好狀態(tài).
組合邏輯和時(shí)序邏輯分開(kāi)用不同的進(jìn)程
組合邏輯包括狀態(tài)譯碼和輸出,時(shí)序邏輯則是狀態(tài)寄存器的切換
必須對(duì)所有狀態(tài)都處理,不能出現(xiàn)無(wú)法處理的狀態(tài),使?fàn)顟B(tài)機(jī)時(shí)空
Mealy狀態(tài)機(jī)輸出不僅取決于當(dāng)前狀態(tài),還與輸入有關(guān);Moore狀態(tài)機(jī)輸出僅與當(dāng)前狀態(tài)有關(guān).
Mealy狀態(tài)機(jī)的例子如下:
... regCurrentState,NextState,Out1; parameterS0 =0, S1 =1; always@(posedgeClkornegedgeRst_) if(!Rst_) CurrentState <= S0; ? ? ? ?else? ? ? ? ? ? ?CurrentState <= #u_dly NextState; ? ?always@(In1?or?In2?or?CurrentState) ? ? ? ?case(CurrentState) ? ? ? ? ? ? S0:begin? ? ? ? ? ? ? ? ?NextState <= #u_dly S1; ? ? ? ? ? ? ? ? Out1 <= #u_dly?1'b0; ? ? ? ? ? ?end? ? ? ? ? ? ?S1:begin? ? ? ? ? ? ? ? ?if(In1)begin? ? ? ? ? ? ? ? ? ? ?NextState <= #u_dly S0; ? ? ? ? ? ? ? ? ? ? Out1 <= #u_dly !In2; ? ? ? ? ? ? ? ?end? ? ? ? ? ? ?end? ? ? ? ?endcase
13.Module 編寫(xiě)示例
/*==============================================================================================*/ Filename : module_name.v Author : Dongyi Lin Description : Called by : Topmodule Revision History : 22-05-27 Revision : 1.0 Email : lindongyi@163.com Company : Hunan Institute of Advanced SensingandInformation Technology, Xiangtan Univeristy Copyright : 2022, Xiangtan University, All right reserved/*==============================================================================================*/modulemodule_name( Output_ports, //comment:port description Input_ports, //comment:port description Io_ports, //comment:port description Clk_port, //comment:port description Rst_port //comment:port description);//port declarations output [31:0] Dataout; input [31:0] Datain; inout Bi_dir_siginal; input input1; input2; //interrnal wire/reg declarations wire [31:0] internal_data; reg output_enable; //module instantiations, Self-build module module_name1 Uinstance_name1( .port1(...); .port2(...); ); module_name2 Uinstance_name2( .port1(...); .port2(...); ); //TSC4000 cell DTC12V1( .Clk(Clk), .CLRZ(Clr), .D(Data), .Q(Qout) );//always block always@(input2)begin ... end//function and task definitions function[function_type] function_name; declarations_of_inputs; [declarations_of_local_variables]; begin behavirol_statement; function_name = function_express; end endfunction endmodule
14.Testbench 編寫(xiě)示例
下面是一個(gè)格雷碼的測(cè)試模塊:
module TB_GRAY; reg Clock; reg Reset; wire [7:0] Qout; integer fout; //輸出文件指針 parameter CYC = 20; GRAY DUT( .Clock(Clock), .Reset(Reset), .Qout(Qout) ); initial begin Clock = 1'b0; Reset = 1'b1; #(5*CYC) Reset = 1'b0; #(5*CYC) Reset = 1'b1; #(5000*CYC); $fclose(fout); $finish; end initial begin $shm_open("GRAY.shm"); $shm_probe("AS"); fout = $fopen("gray.dat"); end always#(CYC)Clock = ~Clock; //輸出數(shù)據(jù)到文件gray.dat always@(posedge Clock)begin $fwrite(fout,"%d %b ", Qout, Qout); end endmodule
在testbench中避免使用絕對(duì)的時(shí)間,如#20,#15或#(CYC + 15)等,應(yīng)該在文件前端使用parameter定義一些常量,使得時(shí)間的定義像#(CYC + OFF0)這樣的形式,便于修改;
觀測(cè)結(jié)果可以輸出到波形文件GRAY.shm,或數(shù)據(jù)文件gray.dat.生成波形文件可以使用simwave或gtkwave觀測(cè)結(jié)果,比較直觀;而生成數(shù)據(jù)文件則既可以快速定位,也可以通過(guò)編寫(xiě)的小程序工具對(duì)它進(jìn)行進(jìn)一步的處理;
對(duì)大的設(shè)計(jì)的頂層方針,一般不要對(duì)所有信號(hào)進(jìn)行跟蹤,大的設(shè)計(jì)波形文件會(huì)很大,仿真時(shí)間也會(huì)延長(zhǎng),可以有選擇的觀測(cè)一些信號(hào).
-
模塊
+關(guān)注
關(guān)注
7文章
2771瀏覽量
49049 -
Verilog
+關(guān)注
關(guān)注
28文章
1364瀏覽量
111461 -
波形
+關(guān)注
關(guān)注
3文章
386瀏覽量
32003
原文標(biāo)題:Verilog編寫(xiě)規(guī)范
文章出處:【微信號(hào):gh_9d70b445f494,微信公眾號(hào):FPGA設(shè)計(jì)論壇】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論