Verilog编码规范.docx
《Verilog编码规范.docx》由会员分享,可在线阅读,更多相关《Verilog编码规范.docx(11页珍藏版)》请在冰豆网上搜索。
Verilog编码规范
Verilog编码规范
(仅供内部使用)
拟制:
xxx
日期:
xxx
审核:
审核者
日期:
yyyy-mm-dd
批准:
批准者
日期:
yyyy-mm-dd
版权所有XX
修订记录
修订日期
修订版本
描述
修订者
1命名规范6
2代码编写规范8
版面8
编写代码规范8
3电路设计规则17
时钟17
复位17
避免LATCH18
避免组合反馈18
赋值语句18
case语句和if-then-else语句19
状态机19
异步逻辑21
4模块划分21
5提高可移植性的编码风格21
采用参数化设计21
采用独立于工具平台和工艺库的设计22
尽量使用已经得到验证的IP22
6其他一些设计建议23
7附件25
8参考文档:
30
基本原则:
简单,一致,可重用。
简单指尽量使用简单的语句,尽量使用简单的设计,尽量使用简单的时钟,尽量使用简单的复位。
一致指尽量保持代码风格一致,尽量保持命名一致。
可重用指有成熟的IP尽量使用IP,设计的代码要尽量可重用。
1
命名规范
给信号命名就像给孩子取名字一样,有区别,有根源,有深度,还有一点,要简单,别冗长。
有区别指取名字不要一样,假如大家只有一个手机号码,那这个号码还能有什么用处?
有根源指取名字要能象姓氏一样,让人一看就直到是张家的后代而不是李家的。
有深度就是取名字要有涵义,张一,张二,张三虽然也是名字,但是请考虑一下被取名字人的感受。
简单点,几十个字母长的名字,打字的和看字的都累。
大小写规则:
只有parameter,`define和module名称才能享受大写。
Module名应与文件名保持一致(文件名是小写),假如不想在设计后面遇到麻烦的话。
不要尝试使用任何保留字,因为他们已经被保留了。
不要重复使用同样的名字去命名不同的数据。
(建议)对module名加”_LVx”的后缀,增强module名称的结构层次含义
如:
设计顶层为TOPLEVEL,即LEVEL1,命名为QTRxxxx_LV1;
时钟模块,IO_PAD,CORE,为LEVEL2,命名为CLK_PROC_LV2等等;
CORE内子模块为LEVEL3,然后以此类推。
对于来自同一驱动源的所有时钟信号使用相同的名字。
对于低电平有效的信号,应该以_n结尾。
模块间相连端口名称要一致。
(建议)使用下表所列的命名缩写方式。
全称
名称
clock
Clk
reset
rst
clear
clr
address
addr
data_in
din
data_out
dout
interruptrequest
int
readenable
rden
writeenable
wren
count
cnt
request
req
control
ctrl
arbiter
arb
pointer
ptr
segment
seg
memory
mem
register
reg
(建议)使用下列后缀命名方式
全称
添加后缀
activelow
_n
enable
_en
select
_sel
flag
_flg
delay
_dly
信号命名的两个词之间用下划线间隔,如ram_addr,cnt_ctrl等等
信号命名尽量不要使用孤立的、小写的英文字母L
2
代码编写规范
2.1版面
语句独立成行,增加可读性和可维护性。
行的长度
保持每行小于或等于72个字符。
因为有的终端或打印机每行不能超过80个字符。
规定72个字符是为了留出边空,提高可读性。
还有一个原因是为象vi这样的编辑器留有显示行号的地方。
用回车来分割超过72个字符的行,并且在下一行用缩进来表示该行是前一行的继续。
缩进。
用缩进来提高续行和嵌套循环的可读性。
缩进采用4个空格。
避免使用TAB键。
不同的编辑器或用户环境使得TAB的位置差别很大,造成缩进的混乱。
有一些工具可以将TAB替换成空格。
(建议)使用注释
使用注释来解释端口、信号、信号组、always块、函数等。
注释应该放在它所描述的代码的附近。
注释应该简明扼要,并足够说明问题。
避免注释杂乱。
显而易见的功能不用加注释。
注释关键是说明设计意图。
2.2编写代码规范
在源文件中要有文件头
在源文件、script文件的开始应包含一个文件头。
文件头至少应包含下列信息:
文件名、作者、模块的功能描述和关键特征的列表、文件产生的日期、更改记录(日期、更改者、更改的内容)。
(参见代码模板)
模块名称用大写,例如:
moduleMEM_CTRL。
端口声明时每行声明一个端口,并有注释(最好在同一行),也可对同一类型的一组端口加注释。
对于时钟,复位以及其他控制信号,需要注释有效工作沿或者有效工作值
建议用下述顺序声明端口。
.)
if(...)d0=A+B;
elsed0=C+D;
中,DC可能只会生成一个加法器。
条件算子中不存在资源共享
如:
z=(cond==1’b1)?
(a+b):
(c+d);
必须使用两个加法器;
而等效的条件if-else语句可以资源共享,如:
if(cond==1’b1)
z=(a+b);
else
z=(c+d);
只要加法器的输入端复用,就可以实现加法器的共享,使用一个加法器实现。
(d)尽量采用公共子表达式
如:
x=a+b+c
y=d+a+b
改为:
z=a+b
x=z+c
y=d+z
(2)算符
(a)条件运算符
r1=gate?
r2:
r3;
避免使用条件嵌套:
r1=(aa=0)?
((bb==0)?
r2:
r3):
r4;or
r1={aa,bb}==0?
r2:
{aa,bb}==0?
r3:
{aa,bb}==0?
R4:
r4;
(b)逻辑操作符
在if(),while(),()?
A:
B之类的表达式中,括号中的表达式应该是一个逻辑表达式,相应的操作符应该用逻辑操作符。
如:
wirex,A,B;
(x)?
A:
B与(x==1'b1)?
A:
B
If(A&B)与if((A&&B)==1’b1)
While(A=B)与while(A==B)
操作结果相同,但显然前者不规范。
(c)乘法运算符“*”
对于一个变量data与常数constant相乘data*constant,如果常数不是2的整数次幂,建议先将其分解,如constant=53=32+16+4+1=2^5+2^4+2^2+2^0,这样乘积就可以表示为变量data移位结果的相加。
对于乘法运算符“*”,综合后通常得到的是乘法器,时延较大。
赋值语句
(1)不要在信号列表中进行运算操作
如:
Bad:
addr(a,b,d&e);
Good:
addr(a,b,c);c=d&e;
(2)BLOCK赋值和NON-BLOCK赋值的使用
(a)组合逻辑采用BLOCK赋值(=)
如:
always@(dat)
i_dat=dat;
(b)非组合逻辑(主要是寄存器)采用NON-BLOCK赋值并加delay以保证前仿真和后仿真的一致
如:
always@(posedegclk)
q<=#`DELd;
(3)在同一块语句中不允许同时出现阻塞赋值和非阻塞赋值
条件语句
(1)IF语句
(a)向量比较时,比较的向量长度要相等,同样向量和常量比较时长度也要求匹配,长度不同时要求进行显式位扩展(verilog对位数小的向量做0扩展以使它们的长度相匹配,该扩展是隐式的)
如:
reg[7:
0]abc;
reg[3:
0]def;
.......
if(abc=={4'b0,def})begin
.......
if(abc==8'h0)begin
(b)不要采用if表达式的简写形式
例如:
if(variable)等同于if(variable!
=0)
if(!
variable)等同于if(variable==0)
但后者才合乎规范
(c)每个if都应该有一个else与之相对应,如果条件为假时不进行任何操作,则用一条空语句else;避免产生latch
(d)if...elseif...elseif...else的代码书写格式如下,要注意优先级
if(...)
begin
......
end
else
begin
if(...)
......
else(...)
if(...)
else(...)
end
(d)如果变量在if-else语句中非完全赋值,则应给变量一个缺省值
如:
if(a==b)
begin
v1=2'b01;
v2=2'b10;....
end
always语句
(1)在使用always生成组合逻辑时,敏感表要列全,敏感表中也不能包含没有用到的变量。
Rule:
Combinationalsensitivitylistsshouldinclude
1)Anysignalonrighthandsideofassignment
2)Anysignaliniforcaseexpression
Forexample:
......
modulesense_list_ex(
b,
c,
d
);
1’1’....
end
else
begin
....
end
采用时钟上升沿触发。
有限状态机(FSM)
(1)组合逻辑和时序逻辑分开描述;
COMBINATERIALLOGICFORNEXTSTATELOGICFORCURRENTSTATE1’COMBINATERIALLOGICFORNEXTSTATELOGICFORCURRENTSTATE1’1’1’1’1’1’1’Ltd.
77mcpu_cs,
cpu_addr,
cpu_datain,
cpu_rd,
cpu_we,
.
.
.
.
.
);
77m77mst(rst),
.addr(sts_num),
.clk(clk77m_sys),
.din(din),
.we(1'b1),
.dout_en(1'b1),
out(dout_tmp)
);
endmodule
3参考文档:
1.ReuseMethodolgyManual_2,byMichaelKeatingandPierreBricaud
2.TheTenCommandmentsofExcellentDesigns,byPeterChambers