Verilog coding style
Coding Style
1. 文件书写规范
1.1 文件头格式
文件头包含三部分内容:
-
版权信息声明,该部分保持不变;
-
文件描述:包括文件名、版本信息、日期、作者,特别关注Description项,可以添加使用限制、模块功能说明等内容。
-
日志信息:该日志信息仅用于记录较大改动(如需求变更),对于仿真BUG修正记录则不用放在这里。
//------------------------------------- //COPYRIGHT(c) 2021, huawei //ALL right are reserved. //------------------------------------- // Design information //------------------------------------- //File name :iic_top.v //Version :v0.1 //Date :2021/04/10 //Author :WA //Decription : //------------------------------------- //Log: // v0.1 :initial // //-------------------------------------
1.2 文件命名规则
- 文件名 必须与 模块名相同(模块命名遵照命名规则)。
- 单个文件只能定义一个模块,无论该模块代码行数多少,禁止在单个文件内定义多个模块。
1.3 有效注释
- 单个文件中代码注释(不包含文件头 和 日志信息)不低于30%
- 注释信息采用英文
- 注释说明添加在目标代码的前面,力求准确
2. 变量命名规范
2.1 参数、宏命名规范
参数、宏命名采用 大写字母+下划线+数字 的方式,禁止使用其他类别的字符
//-----------Parameter Define-----------------
parameter DEC_IDLE = 3'h0;
parameter SYS2DEC = 3'h1;
parameter DEC = 3'h2;
parameter DEC2SYS = 3'h3;
parameter DEC_REAL_DONE = 3'h4;
2.2 普通变量的命名
变量命名遵循简洁、清晰、有意义的原则,禁止私有&&随意的命名,好的变量命名能够提高程序的健壮性和可维护性。
-
变量命名采用 小写字母+下划线+数字 的方式,禁止使用其他类别的字符
-
除IP Core外,独立开发模块命名 同 变量命名规则
-
变量命名应表征该变量的具体含义,禁止随意使用a,b,x,temp等没有含义的单个字符串来命名
-
对于低电平有效变量,在名称后面加“_n”或者“_b”,例如rst_n
-
读?写是能信号命名为xxx_we/xxx_re,高电平有效;低电平有效的读写使能信号命名为xxx_wen/xxx_ren,其他高有效使能信号采用后缀“_ena”标记,低有效使能信号采用后缀“、_ena_n”标记
-
边沿变量后缀为“_pos”和“_neg”, 例如ack_pos表示总线响应变量ack的上升沿
always @ (posedge clk or negedge rst_n)begin if(rst_n==1'b1) ncu_ack_1z <= `TD 1'b0; else begin ncu_ack_1z <= `TD i_ncu_ack; end end assign ncu_ack_pos = i_ncu_ack & (~ncu_ack_1z)
-
打拍变量采用“xz”后缀表示,x表示数字;禁止组合逻辑采用“_z“命名
[email protected](posedge clk)begin drx_data_1z <= i_drx_data; drx_data_2z <= drx_data_1z; drx_data_3z <= drx_data_2z; drx_data_4z <= drx_data_3z; end
-
【推荐】对于流水线处理业务推荐采用”xstg“命名方式,x表示数字,stg取stage缩写。优点:流水线划分明确,便于调试。下图为 UART接口接收端到APB-S端转换的设计方案:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9zwxEHv1-1618033851392)(coding style.assets/image-20210410100413267.png)]
如图采用_xstg命名方式,所有变量对应的层次明确,例如rx_data_2stg只在rx_vld_2stg而非rx_vld_1stg有效时有效。该命名凡是可以有效避免”_xd“类变量作为判断条件时产生混乱
2.3 端口变量命名
由于顶层连线工作量庞大且容易出错,端口命名规范区分以及模块和低级子模块。
- 对于以及模块,端口命名规则如下:
- 输出端口的命名格式:o_输出模块_信号名称,输出端口以小写的字母o加下划线开头,后面跟输出模块的模块名,后缀以可表征端口功能的信号名。例如:o_cpm_fc_clk,该名称表示变量是CPM模块的输出,功能是作为FC的clock。
- 输入端口的命名格式:i_输出模块_信号名称,输入端口以小写的字母i加下划线开头,后面跟输出模块的模块名,后缀以可表征端口功能的信号名。例如:i_cpm_fc_clk,该名称表示模块的输入,来源是CPM模块,功能是FC clock
- 【推荐】输入配置信号:i_scfg信号名称:例如i_scfg_interlve_ena,表示ECC校错码使能。scfg表示static config。在逻辑设计中存在大量静态配置信号(该型号在逻辑/芯片运行过程中不会轻易改变),如果该类信号大量应用在高频时钟域,那么就会造成时序紧张,但实际上对这类信号的时序要求并不需要非常苛刻,通过名称加以区别,在后端中放宽时序约束,有利于提高项目时序性能。
2.4 推荐变量缩写
全称 | 缩写 | 中文含义 |
---|---|---|
acknowledge | ack | 应答 |
address | addr(ad) | 地址 |
arbiter | arb | 仲裁 |
check | chk | 校验,如CRC校验 |
clock | clk | 时钟 |
config | cfg | Configuration,配置 |
control | ctrl | 控制 |
count | cnt | 计数 |
data in | din(di) | 数据输入 |
data out | dout(do) | 数据输出 |
decode | de | 译码 |
decrease | dec | 减一 |
delay | dly | 延迟 |
disable | dis | 不使能 |
error | err | 错误(指示) |
enable | ena | 使能 |
frame | frm | 帧 |
generate | gen | 生成,如CRC生成 |
grant | gnt | 申请通过 |
increase | inc | 加一 |
input | in(i) | 输入 |
length | len | (帧、包)长 |
nmport | nm | 网管相关 |
output | out(o) | 输出 |
packet | pkt | 与帧相同 |
priority | pri | 优先级 |
pointer | ptr | 指针 |
rd enable | ren | 读使能 |
read | rd | 读(操作) |
ready | rdy | 应答信号或准备好 |
receive | rx | (帧数据)接受 |
request | req | 服务、仲裁请求 |
reset | req | |
segment | seg | |
source | src | 源(端口) |
statistic | stat | 统计 |
timer | tmr | 定时器 |
switch | sf | Switch fabric |
temporary | tmp | 临时 |
transmit | tx | 发送(数据帧)相关 |
Valid | vld(v) | 有效、校验正确 |
wr enable | wen | 写使能 |
write | wr | 写操作 |
3. 编码规范
3.1 缩进&&排版格式说明
- 统一缩排取4个空格宽度:Gvim下Tab必须转义成4个空格键,否则禁止使用Tab键
- Begin-end排版方式见下图:如果只有一条语句,那么begin-end可以省略
[email protected](posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
mcu_ack_1stg <= 1'b0;
mcu_ack_2stg <= 1'b0;
end else begin
mcu_ack_1stg <= `TD i_mcu_ack ;
mcu_ack_2stg <= `TD mcu_ack_astg;
end
end
3.2 模块端口声明
模块端口声明推荐采用下图左侧的声明法师,规则为:
-
声明应简介高效,对于同一信号的所有属性(如wire/reg、位宽方向)一次性全部声明,避免多处声明
-
属于同一组的段楼应排布在一起,组成信号再按照input/output分开声明
-
不同组织间信号由空行/注释进行区分
module Sample( input clk ; input rst_n ; //DATA RX Access RAM Interface output reg o_drx_ramce ; output reg o_drx_ramwe ; output reg [7:0] o_drx_rambs ; output reg [31:0] o_drx_ram_A ; output [DATA_WID-1:0:0] o_drx_ram_D ; input [DATA_WID-1:0:0] i_drx_ram_Q ; input i_drx_ramvalid ; //Error Correct & Save DMA Status Access RAM Interface output reg o_esc_ramwe ; output reg [7:0] o_esc_rambs ; output reg [31:0] o_esc_ram_A ; output [DATA_WID-1:0:0] o_esc_ram_D ; input [DATA_WID-1:0:0] i_esc_ram_Q ; input i_esc_ramvalid ; );
3.3 模块例化
在模块实例化时,端口信号传递必须基于名称,禁止基于顺序。且例化模块名称必须是U_xxx.
fc_syn U_fifo_chk_st0_syn(
.rst_n_cki (i_cpm_fc_trx2_rst_n ),
.rst_n_cko (i_cpm_fc_rst_n ),
.clki (i_cpm_fc_trx1_clk ),
.clko (i_cpm_fc_trx1_clk ),
.sigi_p (chk_st0_ok_txrx ),
.sigo_s (chk_st0_ok_sys )
);
3.4 模块内部变量声明
变量命名见“见信号命名规范”小节
- 变量声明时要要注意分组性:有相关性的信号定义在一起,信号组之间可以通过注释或者空行来分隔开。禁止随意地定义和代码中间定义
- 全部变量复位处理
- 各个模块内部都采用异步复位模式,项目统一在某个特定模块内做异步复位同步化处理
3.5 降序定义数组
使用降序定义向量有效位顺序,最低为为0
wire [7:0] rx_ori_data8 ;
wire [15:0] rx_ori_data16 ;
reg rx_ram_data_updata;
3.6 【推荐】禁止使用for、generate、数组
3.7 逻辑复杂度:if…else 和 ?:
“if else”结构:适用于复杂脚尖判断的语句;运算符?:适用于简单条件判断的语句。对于复杂逻辑,采用if…else,对于规则性的或者简单的可以用?:
assign rx_ori_data8 = o_rx_ori_dcnt[1:0] == 2'h0 ? rx_ori_data[7:0] :
o_rx_ori_dcnt[1:0] == 2'h1 ? rx_ori_data[15:8] :
o_rx_ori_dcnt[1:0] == 2'h2 ? rx_ori_data[23:16] :
rx_ori_data[31:24] ;
3.8 "if…else"结构和“case”结构
if…else结构综合的结构可能时与或非门构成的,也可能是一组多路选择器,而case结构综合的结果一般回事多路选择器,但对于可以优化的case综合工具汇总和出更简单的结构。所以对于可以写成平行结构的条件,优先写成case结构,例如地址译码等,条件之间有重复和嵌套清华则写成if…else结构。
3.9 ()和“”
当逻辑条件比较复杂时,用()来隔开各个分条件的边界,避免由运算符优先级不同导致的歧义
if(&a==1'b1 && !flag==1'b1 || b==1'b1) ×
if((&a==1'b1) && (!flag==1'b1) || (b==1'b1)) √
3.10 FSM统一使用三段式状态机
3.11 阻塞赋值与非阻塞赋值
- 时序电路建模时,用非阻塞赋值
- 锁存器电路建模时,用非阻塞赋值
- 用always块建立足额逻辑建模时,用阻塞赋值
- 禁止在同一个always块中混用非阻塞赋值和阻塞赋值
- 在阻塞赋值时不要使用延迟
3.12 always单变量赋值
- 禁止在多个always块中对同一bit变量进行赋值
- 推荐在单个always块只驱动同一个变量
3.13 时序逻辑与组合逻辑
-
禁止用非时钟信号作为时序敏感列表
input clk ; input rst_n ; input i_rx_vld ; input [7:0] i_rx_data ; reg [7:0] rx_data_1stg ; [email protected](posedge clk or negedge rst_n)begin if(rst_n==1'b0) rx_data_1stg <= `TD 8'h0; else if(i_rx_vld == 1'b1) rx_data_1stg <= `TD i_rx_data; else ; end √ [email protected](posedge i_rx_vld or negedge rst_n)begin if(rst_n==1'b0) rx_data_1stg <= `TD 8'h0; else rx_data_1stg <= `TD i_rx_data; × end
-
时序逻辑需要加延时时,利于仿真查看。组合逻辑禁止使用延时。
assign rx_ori_data8 = o_rx_ori_dcnt[1:0] == 2'h0 ? rx_ori_data[7:0] : o_rx_ori_dcnt[1:0] == 2'h1 ? rx_ori_data[15:8] : o_rx_ori_dcnt[1:0] == 2'h2 ? rx_ori_data[23:16] : rx_ori_data[31:24] ; √ assign rx_ori_data8 = `TD o_rx_ori_dcnt[1:0] == 2'h0 ? rx_ori_data[7:0] : o_rx_ori_dcnt[1:0] == 2'h1 ? rx_ori_data[15:8] : o_rx_ori_dcnt[1:0] == 2'h2 ? rx_ori_data[23:16] : rx_ori_data[31:24] ;×
3.14 禁止使用三态信号
各个以及模块及下级模块内部禁止使用三态信号
3.15 跨时钟域信号处理
模块内的所有跨时钟域逻辑集中到同一子模块内,方便维护及后续的流程
3.16 模块端口例化只能直连
顶层Asic body不能包含glue logic,只能直连,禁止有组合逻辑,禁止在实例化的时候直接取反
fc_syn U_fifo_chk_st0_syn( .rst_n_cki (i_cpm_fc_trx2_rst_n ), .rst_n_cko (i_cpm_fc_rst_n ), .clki (i_cpm_fc_trx1_clk ), .clko (i_cpm_fc_trx1_clk ), .sigi_p (chk_st0_ok_txrx ), .sigo_s (chk_st0_ok_sys ) √ ); fc_syn U_fifo_chk_st0_syn( .rst_n_cki (i_cpm_fc_trx2_rst_n ), .rst_n_cko (i_cpm_fc_rst_n ), .clki (i_cpm_fc_trx1_clk ), .clko (i_cpm_fc_trx1_clk ), .sigi_p (chk_st0_ok_txrx ), .sigo_s ((chk_st0_ok_sys&sig_en)) × );
3.17 FPGA宏
_st0_syn(
.rst_n_cki (i_cpm_fc_trx2_rst_n ),
.rst_n_cko (i_cpm_fc_rst_n ),
.clki (i_cpm_fc_trx1_clk ),
.clko (i_cpm_fc_trx1_clk ),
.sigi_p (chk_st0_ok_txrx ),
.sigo_s ((chk_st0_ok_sys&sig_en)) ×
);
### 3.17 FPGA宏
当有为适配FPGA结构而作的代码修改,要能被全局宏”FPGA“控制,当这个宏没有被定义时,针对FPGA的所有特定逻辑要被屏蔽掉。
推荐阅读
-
error: style attribute ‘@android:attr/windowEnterAnimation’ not found.
-
Zen Coding 快速编写HTML/CSS代码的实现
-
Zen Coding css,html缩写替换大观 快速写出html,css
-
style属性
-
vue.js入门教程之绑定class和style样式
-
基于android样式与主题(style&theme)的详解
-
学习vue.js中class与style绑定
-
调侃江南Style的冷笑话
-
哈夫曼编码的理解(Huffman Coding)
-
HOWTO change ToggleSwitch’s Style on WP7