VerilogHDL程序编写规范2.docx
《VerilogHDL程序编写规范2.docx》由会员分享,可在线阅读,更多相关《VerilogHDL程序编写规范2.docx(37页珍藏版)》请在冰豆网上搜索。
VerilogHDL程序编写规范2
VerilogHDL程序编写规范
版本号:
1.0
编写者:
刘兆庆
状态:
试用
发布日期:
2008年月日
摘要
本文定义了VerilogHDLRTL编码规则和指南,按照本文介绍的方法进行编码,有助于使VerilogHDLRTL代码具有良好的可读性、可修改性和可重用性,同样也有助于综合和仿真。
文档控制表
表1文档控制表
文档
标题:
版本号:
发行号:
VerilogHDL程序编写规范
V1.0
实行日期:
关键词
2008年6月1日
编辑工具
名称
Microsoft®OfficeWord2003
模板:
作者情况
原作者:
刘兆庆
协作者:
罗杰俊
校对:
审核:
文档状态表
表2文档状态表
标题
VerilogHDL程序编写规范
ID号
版本号
发行号
日期
更改原因
1.0
0
2008.03.20
试发布
1.0
1
2008.06.01
补充内容
目录
1概述1
1.1目的1
1.2所面向的对象1
1.3文档的组织结构2
2基本编码规范2
2.1命名规范:
2
2.2源文件中信息头书写规范4
2.3注释书写规范5
2.4代码书写规范5
2.5端口声明规范6
2.6端口映射和常量映射8
2.7立即数的使用8
2.8编辑器9
2.9语法规则9
2.9.1模块9
2.9.2变量10
2.9.3参数11
2.9.4function和task12
2.9.5其他规则12
3时钟和复位信号设计规范13
3.1避免使用混合时钟沿13
3.2避免使用时钟缓冲器14
3.3避免使用门控时钟14
3.4避免在模块内部产生时钟15
3.5门控时钟和低功耗设计15
3.6避免在模块内部产生复位信号16
3.7复位逻辑功能17
3.8一位同步器17
3.9多位同步器17
4可综合性编码规范18
4.1寄存器描述18
4.2避免产生锁存器18
4.3避免产生组合电路反馈。
19
4.4完整的敏感量列表20
4.5阻塞和非阻塞赋值21
4.6case语句和if-else语句23
4.7时序逻辑电路的描述24
4.8对关键信号的描述25
4.9避免使用延时语句25
5可综合划分规范25
5.1所有输出采用寄存器输出25
5.2将相关的组合逻辑放在同一模块26
5.3将具有不同设计目标的部分分配到不同模块中27
5.4异步逻辑27
5.5避免时序设计中的例外情况27
5.6消除顶层模块中的胶连逻辑电路28
1概述
本文的编码指南基于几个基本原则。
最基本的目标是,要求开发出来的RTL代码简单,而且规范。
简单且规范的结构比复杂的结构更容易设计、编码、验证和综合。
在满足功能和性能的前提下,这个可重用设计的目标是尽可能简单。
编码指南详细描述了以下几个值得推荐的建议。
●使用简单结构、基本类型和简单的时钟规划;
●使用一致的编码方式,一致的命名习惯,一致的过程和状态机;
●使用规则的划分方法,所有模块采用寄存器输出,模块大小尽量一致;
●为了让RTL代码容易理解,编码中使用注释,使用有意义的命名方式,使用常用或参数代替立即数。
在这些原则指导下,开发者能够更容易编码,达到理想的性能、功能、时序、功耗和面积。
1.1目的
本文档的目的是定义一个VerilogHDL编码标准,编写VerilogHDL代码时必须遵循该标准的规定。
这一标准的提出,可以为VerilogHDL编程者提供以下便利:
●避免犯低级错误
●便于不同程序员的维护
●便于程序的移植和复用
●便于阅读和理解
●具有一致的书写风格
另外请注意,本文档都不能替代VerilogHDL的编程书籍。
1.2所面向的对象
本文档面向哈尔滨工业大学自动化测试与控制研究所所有从事VerilogHDLRTL程序编写的人员。
1.3文档的组织结构
文档组织如下:
1.概述;
2.基本编码规范,同时给出解释和例子;
3.时钟和复位信号设计规范,同时给出解释和例子;
4.可综合性编码规范,同时给出解释和例子;
5.可综合划分规范,同时给出解释和例子;
2基本编码规范
2.1命名规范:
在整个设计中一直遵守命名习惯有助于提高代码的可读性,同样也有助于代码的调试、检查、维护和修改。
具体规范如下:
规则——为设计开发命名习惯。
以文档的形式规定下来,并在整个设计中一直遵守命名习惯。
指南——变量名、模块名、参数和端口名使用小写字母。
指南——常数(`define)使用大写字母。
指南——信号、端口、函数和参数命名时采用有意义的名称。
例如,不要用ra命名RAM地址,而应该用ram_addr。
指南——对时钟信号使用一致的命名方式,例如clk。
如果有一个以上的时钟信号,使用clk作为所有时钟信号的前缀(例如:
clk1、clk2或clk_interface等)。
指南——对于低有效信号,信号名称尾部用下划线加小写字母n,如_n。
指南——对复位信号使用一致的命名方式,如rst。
如果复位信号是低有效的,则可以使用诸如rst_n的名称。
规则——在描述多个总线时,使用由大到小的位排列顺序。
即[x:
0]或[0:
x]。
使用一致的位排列顺序有助于提高代码可读性,减少总线连接时偶尔发生的位排列顺序不一致的情况,如例1.1所示。
例1.1使用[x:
0]端口声明
moduleDW_addinc#(
parameterwidth=8
)(
input[width-1:
0]a,
input[width-1:
0]b,
inputci,
input[width-1:
0]sum,
output[width-1:
0]co
);
endmodule
指南——连接的端口与信号使用相同或类似的名称(例如,a=>a;或a=>a_int)。
指南——模块的端口命名必须根据不同类型选择不同的后缀,命名格式为“*_后缀”,后缀如表1所示。
表1信号命名习惯
后缀
用法
*_a
异步信号(例如,addr_strobe_a)
*_pn
第n段中使用的信号(例如,enable_p2)
*_nxt
数据在被寄存到相同名称的寄存器之前
*_i
输入信号
*_o
输出信号
*_n
低电平或下降沿有效的信号
如果端口信号具有多个属性,则后缀为多个后缀的任意顺序组合。
例如:
输入输出信号的后缀应选为“io”或“oi”,模块端口命名的其他规则,和变量命名相同。
2.2源文件中信息头书写规范
规则——在每一个源文件的开始,都必须包含一段注释,信息头部分。
脚本文件也是如此。
信息头部分必须包含:
a.法律声明,包括机密性、版权、复制时的限制
b.文件名
c.作者
d.模块功能和主要特征描述
e.文件创建日期
f.修改历史记录,包括日期、修改者姓名及对变化的描述
例1.2展示了一个源文件头。
例1.2一个VerilogHDL源文件头
//Thisconfidentialandproprietarysoftwaremaybeusedonlyas
//authorizedbyalicensingagreementfromSynopsysInc.
//Intheeventofpublication,thefollowingnoticeisapplicable.
//
//©COPYRIGHT1996SYNOPSYSINC.
//ALLRIGHTSRESERVED
//
//Theentirenoticeabovemustbereproducedonallauthorizedcopies.
//
//Filename:
DWpci_core.v
//Author:
张三
//Date:
09/17/96
//Version:
0.1
//Abstract:
Thisfilehastheentity,architectureandconfiguration
//ofthePCI2.1MacroCellcoremodule.
//Thecoremodulehastheinterface,config,initiator,
//andtargettop-levelmodules.
//
//ModificationHistory:
//DateByVersionChangeDescription
//=============================================
//09/17/96JDH0.1Original
//11/13/96JDHLastpre-Atriachanges
//03/04/97SKCchangesforism_ad_en_ffd_n
//andtsm_data_ffd_n
//
//=============================================
2.3注释书写规范
规则——使用注释大概地解释一下过程、函数和声明类型。
如例1.3所示。
例l.3对子类型声明注释
//CreatesubtypeINTEGER_256forbuilt-inerror
//checkingoflegalvalues.
subtypeINTEGER_256istypeintegerrange0to255;
指南——用注释解释端口、信号、变量或一组信号或变量。
注释应该放在靠近被解释的代码附近。
指南——注释采用简单容易理解的英文,不能使用中文(不同的编译器支持的中文字符不同,会产生不能识别的现象)
指南——全部使用单行注释,只有在开发调试过程中需要注释大段代码时才使用多行注释
指南——/*…/*…*/…..*/这种注释在第一个*/处结束,第二个被忽略,而且会产生语法错误,禁止出现此类注释。
指南——注释应遵循简洁、精炼的原则,禁止使用“注释段”。
指南——一些很明显的功能不需要注释,在代码后面,对关键内容注释。
指南——对过程的注释,放在整个过程的前面,而不是插入过程中,这样可以不中断代码的连贯性。
2.4代码书写规范
规则——代码按照规定格式书写,可提高代码的可读性和可维护性。
指南——每行只能写一条代码(声明或语句)。
指南——每行代码长度最好不要超过72个字符,对于超过72个字符的代码,使用回车符进行分割,在下一行中继续书写上一行的代码。
指南——使用缩进格式书写条件和循环部分代码,如例1.4所示。
例1.4一个嵌套if语句的缩进格式
if(bit_width(m+1)==2)begin
for(i==0;ispin_j=0;
for(j==i;jif(j>spin_j)begin
if(matrix(m)(i-1)(j)!
=wht)begin
if(j==m&&matrix(m)(i)(j)==wht)begin
matrix(m)(i)(j)=j;
elsebegin
for(k==j+1;kif(matrix(m)(i-1)(k)!
=wht)begin
matrix(m)(i)(k)=j;
spin_j=k;
end
end//k
end
end
end
end//j
end//i
end
指南——推荐使用两个空格的缩进格式,如果缩进比较大(例如8格),那么在书写多层嵌套时,可能会遇到每行字长的限制。
指南——避免使用Tab键,在不同的编辑器中对Tab的设置不一致,可能会引起代码的某种混乱。
指南——begin必须与if,while,always,initial,for等词同行,end必须另起一行,begin…end之间的代码必须具有缩进关系
指南——在RTL源文件中,不要使用HDL保留字命名任何信号或变量。
2.5端口声明规范
规则——在声明端口时应遵循逻辑顺序,并且在整个设计中保持一致的声明顺序
指南——每行声明一个端口,紧跟着注释的内容(注释最好在同一行内)。
指南——对于每个接口,端口声明的顺序如下:
输入(input):
时钟(Clocks)
复位(Resets)
使能(Enables)
其它控制信号(Othercontrolsignals)
数据和地址线(Dataandaddresslines)
输出(output):
时钟(Clocks)
复位(Resets)
使能(Enables)
其它控制信号(Othercontrolsignals)
数据(Data)
例1.5端口排列顺序
moduleDW_usbd(
//ExternalClockGenerator:
Inputs
refclk,//MainReferenceClock
//ScanTestInterface:
Inputs
scan_mode,//Forscantesting
//UTMIPHY(type2/3)Interface:
Inputs
//Enables
phy23_rxvalid,//SpecifiesthevaliddataLSB
phy23_rxvalidh,//SpecifiesthevaliddataonMSB
phy23_txready,//Validdatawillbepolled
//Othercontrolsignals
phy23_linestate,//Currentstateofdp,dmlines
phy23_rxerror,//Errorinreceiveddata
phy23_rxactive,//PHYneedstotransmitdata
//Dataandaddresslines
phy23_rx_data,//16_bitunidirreceivedatabus
//UTMIPHY(type2/3)Interface:
Outputs
//Reset
phy23_reset,//ResetsignaltothePHY
//Enables
phy23_suspend_n,//SuspendsignaltothePHY
phy23_xcvr_select,//SelectHSorFStransceriver
//ApplicationInterface:
Inputs
//Resets
app_rst_n,//Asynchronousreset
app_test_mode,//BypassingUSBreset
//APPRegisterR/WInterface:
Inputs
//Enables
app_16bit,//APP16_bitr/waccess
app_reg_sel,//APPRegisterInterfaceselect
//Othercontrolsignals
app_rd_n,//APPregister-readcommand
app_wr_n,//APPregister-writecommand
//Dataandaddresslines
app_addr,//APPRegisteraddressbus
app2usb_data,//APPWrite-databus
//APPRegisterR/WInterface:
Outputs
//Othercontrolsignals
usb2app_drdy,//Datareadyindicationfrom
//DW_usbdtoAPP
//Dataandaddresslines
usb2app_data,//APPRead-Databus
//
//
//
);//DW_usbd
2.6端口映射和常量映射
规则——使用显式的方式映射端口和常量,保持端口名称之间一一对应,不能使用顺序映射方法。
如例1.5所示。
例1.6使用名称对应的映射方法
DW_ram_r_w_s_dff
#(.ram_width(`ram_data_width+`ram_be_data_width),
.fifo_depth(`fifo_depth),
.tco
(1))
U_int_txf_ram(
.clk(refclk),
.rst_n(txfifo_ram_reset_n),
.cs_n(1`b0),
.wr_n(txfifo_wr_en_n),
.rd_addr(txfifo_rd_addr),
.wr_addr(txfifo_wr_addr),
.data_in(txfifo_wr_data),
.data_out(txf_ram_data_out)
);
2.7立即数的使用
指南——在设计中,除0和1以外,不能使用立即数值,而使用参数或常量赋值,如例2.1中所示。
参数或常量赋值有以下优点,
●对于一个设计具有更多的灵活性;
●参数或常量值只需要在一个地方修改;
●参数可以在实例化时重载,提高模块的可重用性;
●编译器可能只支持常量类型,不支持立即数。
例1.7使用参数赋值,不要使用立即数赋值
parameterbus_size=8;
wire[bus_size–1:
0]my_in_bus;
reg[bus_size–1:
0]my_out_bus;
2.8编辑器
指南——建议使用SourceInsight软件。
2.9语法规则
2.9.1模块
指南——模块声明使用如下样式:
例1.8模块声明样式
modulewaveform_generator#(
parameterperiod=100,//注意缩进两个字符
parametertype="sine"
)(//注意括号
inputhold_i,//注意端口命名
outputreg[63:
0]value_o
);
指南——模块命名与普通变量命名类似
指南——模块实例的命名建议以模块名的一部分为前缀
指南——模块实例化时,不能采用按顺序匹配输入输出的方式,而必须使用“.端口名(端口信号)”的方式,参数也必须使用“.参数名(参数值)”方式重新设置参数值,因此模块实例化的格式和其声明的格式相似,例如:
例1.9
waveform_generator#(
.period(100),
.type("sine")
)wg_chnnal_1(
.hold_i(hold),
.value_o(value)
);
指南——每一个可以被调用的模块的最后(endmodule之前)必须给出实例化本模块的典型代码,以方便调用者复制,注释形式为/*...*/,如:
例1.10
/*
waveform_generator#(
.period(100),
.type("sine")
)wg_chnnal_1(
.hold_i(hold),
.value_o(value)
);
*/
指南——每一个模块(可综合或行为模块,包括FPGA顶层设计)必须由与之对应的testbench文件,testbench文件命名必须和模块文件名相同,扩展名使用.vt,testbench的顶层模块建议命名为“被测模块名_tb”。
指南——可综合的模块必须放在一个单独的文件里,且这个文件的文件名必须和这个模块的名字完全相同。
只有仿真文件里可以放多个模块,此时文件名应按文件作用取名,命名方法参见变量命名。
指南——所有模块的仿真时间单位和精度都规定为1ns/1ps,即所有文件的第一条语句必须为“`timescale1ns/1ps”。
2.9.2变量
指南——每一行至多只能定义一个变量
指南——变量必须以小写字母打头,只能包含小写字母和数字和用于分隔单词“_”
指南——变量命名中使用完整单词,除约定缩写以外,约定缩写如下表
完整形式
缩写
Oscillator
osc
Reset
rst
Synchronous
sync
Condition
conf
Manufacture
manf
Parameter
param
Clock
clk
Control
ctrl
Condition
cond
Counter
cntr
Configure
config/cfg
Instance
inst
chip_select
cs
有待添加
指南——如果变量的使用范围较大,建议使用对不同类型的变量使用不同的前缀,即以“前缀_”打头,如下表:
类型
前缀
integer
i
real
r
realtime
rt
time
t
event
ev
genvar
gv
reg
reg
指南——命名必须使用有意义的英文,不得使用拼音
指南——状态机变量命名建议以“state_”打头,如果模块内