Verilog的代码编写规范
- 对于代码的编写规范,并没有统一的标准,我也在编写的过程中逐步模仿他人的代码,不断改进自己的代码风格,以下内容只是个人的一些整理总结,不保证足够规范,我也会进行逐步的完善。
常用命名规则
- 所有的信号(signal),变量(variable)以及模块(module)的名字都用小写字母,常量名(参数(parameter)和宏(macro))用大写字母。不要依赖大小写给标识符增加语义。
- 文件名
- 对象(小写) +功能(小写).v
ddr_ctrl.v
- 模块名
- 对象(大写)+ 功能(大写)
- 如果该模块为顶层模块,则+TOP
DDR_INST
DDR_CTRL_TOP
- 元件例化名
- 例化名前加大写U_以区分(多次例化可另加标识,如最简单的U1_,U2_)
U_DDR_INST
- 常量命名
- 常数、DEFINE和参数必须用大写字母定义。不允许将大小写字母混用来表示词的间隔,应该用下横线来表示词间隔
- 命名的总体规则为:对象+含义
DDR_ADDRESS = 8'b0010_1100;
- 信号命名
- 所有信号的命名均采用小写
- 命名的总体规则为:对象+功能(+极性+特性)
- 对象为该信号归属的模块,功能为该信号的具体用处
sys_rst_n
fifo_cnt
- 时钟和复位信号命名
- 对于时钟信号,使用前缀clk_*,并使用有含义的缩写构成时钟信号。
- 对于复位信号,使用前缀rst_*,并使用有含义的缩写构成复位信号。
clk_base_61M44 , rst_lbus_n;
常用功能缩写
全称 | 缩写 | 含义 |
---|---|---|
acknowledge | ack | 应答 |
adress | addr(ad) | 地址 |
check | arb | 仲裁 |
arbiter | chk | 校验,如CRC校验 |
clock | clk | 时钟 |
config | cfg | 配置 |
control | ctrl | 控制 |
count | cnt | 计数 |
data in | din(di) | 数据输入 |
data out | dout(do) | 数据输出 |
decode | de | 译码 |
decrease | dec | 减1 |
delay | dly | 延迟 |
disable | dis | 不使能 |
error | err | 错误(指示) |
enable | en | 使能 |
frame | frm | 帧 |
generate | gen | 生成,如CRC生成 |
grant | gnt | 申请通过 |
increase | inc | 加1 |
input | in(i) | 输入 |
length | len | (帧/包)长度 |
output | out(o) | 输出 |
priority | pri | 优先级 |
pointer | ptr | 指针 |
rd_enable | ren | 读使能 |
read | rd | 读操作 |
ready | rdy | 应答信号或准备好 |
receive | rx | (帧数据)接收 |
request | req | (服务/仲裁)请求 |
reset | rst | 复位 |
source | src | 源(端口) |
timer | tmr | 定时器 |
transmit | tx | 发送相关 |
valid | vld(v) | 有效,校验正确 |
wr enable | wen | 写使能 |
write | wr | 写操作 |
代码书写范例
/**********************************************************************
* Copy(c) 1906, Jinan University
* All right reserved
*
* Company :
* Author :
* Email :
*
* Filename : LED_run //文件名小写
* Description :
* Call by :
* Revision History :
*
**********************************************************************/
// DEFINE(S)
`define //函数名、宏定义、参数定义用大写
// TOP MODULE
module MODULE_NAME( //模块名大写,对应文件名的小写
//端口定义按照输入,输出,双向的顺序
//输入输出信号的宽度定义与关键字之间,信号名与宽度之间要用空格分开
//端口、信号、变量名的所有字母小写
//基于含义命名(避免以数字命名的简单做法),含义可分段,每一小段之间加下划线”_”
//如 tx_data_val;命名长度一般限制在 20 个字符以内。
//INPUT
input rst_n, //复位信号,_n代表低电平有效,_p高电平有效
input clk_*, //*指代时钟频率,如clk_50M,代表50MHz时钟
input [i:0] a_din,
input [j:0] b_din,
//OUTPUT
output [m:0] a_dout,
output [n:0] b_dout,
//INOUT
inout [p:0] a_dinout,
inout [q:0] b_dinout
);
// DEFINE PARAMETERS
parameter //函数名、宏定义、参数定义用大写
// OUTPUT ATTRIBUTE
//REGS
reg [m:0] a_dout ; //***** //端口、信号、变量名的所有字母小写
//不能用 ”reg”,作为最后的后缀名, 因为综合工具会给寄存器自动加上_reg,
//如果命名里就用_reg 作为后缀名则扰乱了网表的可读性。
//WIRES
wire [n:0] b_dout ; //*****
// INNER SIGNAL DECLARATION
//定义内部使用的REGs和WIREs
//REGS
reg [3:0] counter ; //***** //端口、信号、变量名的所有字母小写
//WIRES
wire [7:0] temp1 ; //*****
//INSTANTCE MODULE
//instance of module MODULE_NAME_A filename:module_name_a.v
MODULE_NAME_A U_MUDULE_NAME_A( //例化名在模块名前面加U_
.A (A ),
.B (B ),
.C (C )
);
//*****************************
// MAIN CORE
//*****************************
//Sequential logic style
//不允许有模糊不清的状态机模式,所有的状态机必须清晰明了。
//我们要求将状态机的时序部分和组合逻辑部分分开。
//always中,一定要用 begin end 区分,格式和代码风格统一如下
always @(posedge clk_* or negedge rest_n)
begin : SEQ_BLOCK_NAME
//统一的缩排取4个空格宽度
//赋值或者条件判断时要注明比特宽度,注意表达式的位宽匹配
//复位的条件表达式及命名要和 always 敏感列表中的描述相统一,并且一定要使用异步复
位。 所有的复位必须低有效。
IF (rst_n==1'b0)
counter<=4'b0; // if else 中仅有一个语句行时,不要使用 begin end
else
begin
//一般表达式在运算符的两侧要各留出一个空格
if( (&a==1’b1) && ( !flag==1’b1) ||( b==1’b1) ) //如果一个表达式的分组情况不是很明显时,加上括号有助于理解。
counter <= #`DLY siginal_b;
else; // if else 搭配使用,对于缺省的条件要写”else;”;
end
end // SEQ_BLOCK_NAME
//Combinational logic style
always @(signal_a or signal_b)
begin : COM_BLOCK-NAME
//if else 结构综合的结构可能是与或非门构成的,也可能是一组多路选择器
//而case结构综合结果一般会是多路选择器,但对于可以优化的 case 综合工具会综合出更简单的结构。
//所有对于可以写出平行结构的条件,优先写成 case 结构,例如地址译码等,条件之间
//有重复和嵌套的情况则是写成 if else 结构。
case (expression)
item1 : begin
signal_c=*****;
end
item2 : //statement;
default ://statement; // case 中的缺省条件要写”default”;
endcase
end // COM_BLOCK_NAME
//*********************
endmodule
//无条件寄存的寄存信号在原信号上加 r 、rr,或者加上ff1,ff2
如原信号 data_in, 寄存一拍data_in_r或data_in_ff1, 寄存两拍 data_in_rr,data_in_ff2