一、工程建立规范:
1、工程的组成:
(1) 一个顶层文件夹
(2) 顶层文件夹下,至少包括以下四个子文件夹
a) project文件夹:存放ISE工程文件,包括ise、bit、mac等文件
b) source文件夹:存放verilog源文件
c) explain文件件:存放注释说明文档
d) test文件夹:存放测试程序代码,可进一步分为软件调试程序、硬件调试程序
2、 工程的命令:
(3) 定层文件夹命令为top_xxx,xxx为工程的识别名称
(4) 顶层文件夹的子文件夹分别命名为:project、source、explain、test
二、 RTLCODE 规范
1.标准的文件头
在每一个版块的开头一定要使用统一的文件头,其中包括作者名,模块名,创建日期,概要,更改记录,版权等必要信息。
统一使用以下的文件头:
//**************************************************************
// COPYRIGHT(c)2005, Hislicon Technologies Co, Ltd
// All rights reserved.
//
// IP LIB INDEX : IP lib index just sa UTOPIA_B
// IP Name : the top module_name of this ip,usually, is same
// as the small ip classified name just as UTOPIA
// File name : file_name of the file just as “tx_fifo.v”
// Module name : module_name of this file justas “TX_FIFO”
// Full name : complete Emglish nme of thisabbreviated
//
// Author : Athor/ID
// Email : Author’s email
// Data :
// Version : V 1.0
//
//Abstract :
// Called by : Father Module
//
// Modification history
//------------------------------------------------------------------------------------------------------
// //
// $Log$
//
//*********************************************************************
2. 标准的module格式 (module 整体结构)
对于模块的书写采用统一的格式便于项目内部成员的理解和维护,我们用批处理建立了一个MODULE模块,其内容解释如下:
l 端口定义按照输入,输出,双向的顺序:
l 模块名、模块例化名统一,例化名前加大写U_以区分 (多次例化另加标识 ),三者关系:
文件名 :xxx .v (小写)
模块名 :Xxx (首字母大写)
例化名 :U1_xxx (首字母大写)
IP 内部所有的模块名都要加IP名或者IP名简称作前缀,如USB_CTRL、USB_TX_FIFO。
// *****************************
// DEFINE MODULE PORT //
//******************************
//
// module MODULE_NAME (
// INPUT
input_port_1,
…
input_port_m,
// OUTPUT
output_port_1,
…
output_port_m,
);
//*****************************
// DEFINE PARAMETER //
// ******************************
parameter…
//******************************
// DEFINE INPUT
//******************************
input rst_n ; // reset, active low .
input clk_* ; // clock signal , 50M .
input [n:0] a_din ; // *****
input [k:0] b_din ; // *****
//******************************
// DEFINEOUTPUT //
//******************************
output [m:0] a_dout ; // *****
output [i:0] b_dout ; // *****
//******************************
// OUTPUTATRRIBUTE //
//******************************
// REGS
reg [m:0] a_dout ; // *****
//WIRES
wire [i:0] b_dout ; // *****
//******************************
// INSTSNCEMODULE //
//******************************
MODULE_NAME_A U_MODULE_NAME_A(
.A (A ),
.B (B ),
.C (C ),
); …
//******************************
//MAIN CODE //
//******************************
… …
… …
… …
//****************************** //
Endmodule
3.一致的排版
A. 一致的缩排
l 统一的缩排取4个空格宽度
l 输入输出信号的宽度定义与关键字之间,信号名与宽度之间要用空格分开;所有宽度定义对所有信号名对齐,代码风格统一如下:
input [3:0] input_a ; // *****
input input_b ; // *****
…
output [128:0] output_a ;
output [15:0] output_b ;
output output_c ;
B. 一致的 begin end 书写方式
always 中,一定要用begin end 区分,格式和代码风格统一如下:
always @ (postedge clk or negedge rst_n)
begin
if(rst_n==1’b0)
syn_rst<= ‘DLY 1’b0;
else
begin
if (a==b)
syn_rst<= ‘DLY 1’b1;
else
syn_rst<= ‘DLY 1’b0;
end
end
if else 中仅有一个语句行时,不要使用begin end; 如果有多个语句行时,begin end和if ()或else ()空四个格。
格式如下:
if (…)
…
else if (…)
else
********************************************************************
if (…)
…
else if (…)
begin
…
…(
end
else
4. 一致的信号命名风格
简洁,清晰,有效是基本的信号命名规则,详见命名规范。
全称 | 缩写 | 中文含义 |
acknowledge | ack | 应答 |
adress | 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 | en | 使能 |
frame | frm | 帧 |
generate | gen | 生成,如CRC生成 |
grant | gnt | 申请通过 |
increase | inc | 加一 |
input | in(i) |
|
length | len | (帧、包)长 |
nmport | nm | 网管相关 |
output | out(o) |
|
packet不推荐packet | pkt | 与帧相同 |
priority | pri | 优先级 |
pointer | ptr | 指针 |
rd enable | ren | 读使能 |
read | rd | 读(操作) |
ready | rdy | 应答信号或准备好 |
receive | rx | (帧数据)接收 |
request | req | (服务、仲裁)请求 |
reset | rst |
|
segment | seg |
|
souce | scr | 源(端口) |
ststistics | stat | 统计 |
timer | tmr | 定时器 |
switcher | sf | Switch fabric |
temporary | tmp | 临时 |
transmit | tx | 发送(帧数据)相关 |
Valid | vld(v) | 有效、校验正确 |
wr enable | wen | 写使能 |
write | wr | 写操作 |
a. 端口、信号、变量名的所有字母小写:函数名、宏定义、参数定义用大写
b. 使用简称、缩略词(加上列表)
c. 基于含义命名(避免以数字命名的简单做法),含义可分段(最多分三段),每一小段之间加下划线”_”,如tx_data_val;命名长度一般限制在20个字符以内。
d. 低电平有效信号,加后缀”_n”,如 rst_n
e. 无条件寄存的寄存信号在原信号上加ff1、ff2… 如原信号 data_in, 寄存一拍data_in_ff1,寄存两拍data_in_ff2
f. 不能用 ”reg”,作为最后的后缀名,因为综合工具会给寄存器自动加上_reg, 如果命名里就用_reg作为后缀名则扰乱了网表的可读性。
5.统一的表达式书写
A. 括号的使用
如果一个表达式的分组情况不是很明显时,加上括号有助于理解。
例如下面的代码加上括号就清晰很多。
if (&a==1’b1&&!flag==1’b1 || b==1’b1) //
改为:
if ((&a==1’b1)&&(!flag==1’b1)||( b==1’b1)) //
B.适当的使用空格
一般表达式在运算符的两侧要各留出一个空格,但定义比较长的表达式,去掉预先级高的运算符前的空格,使其与运算对象紧连在一起,可以更清晰的显示表达式结构。
还是上面的例子:
if ((&a==1’b1)&&(!flag==1’b1)||( b==1’b1)) //
改为:
if ((&a == 1’b1)&&(!flag == 1’b1)||( b == 1’b1)) //
”<=”, ”==”前后都要加空格。
C. 赋值要指明比特宽度
赋值或者条件判断时要注明比特宽度,注意表达式的位宽匹配。如:
reg [4:0] signal_a;
错误: 1 signal_a <= 5;
2 if(signal_a == 5)
3 signal_a <= signal_b[3:0]+4;
正确: 1 signal_a <= 5d5
2 if(signal_a == 5d5)
3 signal_a <= {1’b0,signal_b[3:0]+5d4
因为工具默认是32位宽,如果不注明位宽,工具检查会报warning,而且这样增加了设计的严谨性。
6.统一的语句书写――条件判断结构书写方式
A. 条件的完整性
Ifelse搭配使用,对于缺省的条件要写”else;”;
Ifelsed 条件判别式要全面,比如if(a == 1’b0);
Case中的缺省条件要写”default”;
B.”if else”结构:适用于复杂条件判断的语句
但对于复杂的条件判断,使用?:如果不仔细分析条件的每一条路径,就让读代码搞不清它是到底要做什么。例如:
C =(!Ic&&!rc)?0(Ic?rc:Ic) // (?:)
改为:
always @(Ic or rc) // if else
begin
if((Ic==0)&&(rc==0))
c = 0;
else if(Ic==1)
c = rc;
else
c = Ic;
end
即使是简单的条件判断,我们也必须使用IF-ELSE,当涉及复杂的条件判断,使用IF-ELSE结构以获得清晰的结构便于理解和维护。因此必须使用IF-ELSE。
C.”IFELSE”结构VS”CASE”结构
IF ELSE结构综合的结构可能是与或非门构成的,也可能是一组多路选择器,而case结构综合结果一般会是多路选择器,但对于可以优化的case综合工具会综合出更简单的结构。
所有对于可以写出平行结构的条件,优先写成case结构,例如地址译码等,条件之间有重复和嵌套的情况则是写成if else结构。
D. Finite StateMachine
不允许有模糊不清的状态机模式,所有的状态机必须清晰明了。
我们要求将状态机的时序部分和组合逻辑部分分开。
例如:
module state4 (
clock
reset
out
);
input reset
input clock;
output [1:0] out;
parameter [1:0] stateA=2’b00;
parameter [1:0] stateB=2’b01;
parameter [1:0] stateC=2’b10;
parameter [1:0] stateD=2’b11;
reg [1:0] state;
reg [1:0] nextstate;
reg [1:0] out;
always @ (posedge clock)
begin
if (reset ==1,0’b0)
state <= stateA;
else
state <= nextstate;
end
always @ (state)
begin
case (state)
stateA: begin
nextstate = stateB;
end
stateB: begin
nextstate = stateC;
end
stateC: begin
nextstate = stateD;
end
stateD: begin
nextstate = stateA;
end
endcase
end
always@(postdge clock or negedge reset)
begin
if (reset==1’b0)
out <= 2’b0;
else begin
if (state==…)
out <= …;
else
out <= …;
end
end
endmodule
7. 统一格式的always程序块的书写
A.always 中的变量的赋值方式――阻塞与非阻塞赋值
当进行时序逻辑建模时,always块中使用非阻塞赋值――NON_BLOCKING;
参加如下代码:
always @(posedge clk or negedge rst_n)
begin
if (rst_n == 1’b0;
myreg <=1’b0;
else
myreg <=‘DLY1’b1;
end
always块中使用的NON_BLOCKING赋值时在”<=”前要加上#‘DLY,如上例;
当使用always语句进行组合逻辑建模时,always块中使用阻塞赋值――BLOCKING;
参见如下代码:
always @(addr)
begin
case (addr)
2’b00 : cs0_n=1’b0;
2’b01 : cs0_n=1’b1;
2’b10 : cs0_n=1’b0;
2’b11 : cs0_n=1’b1;
default: cs0_n=1’b1;
endcase
end
· 如果要使用always语句同时进行时序与组合逻辑建模时,一定使用非阻塞赋值;例如:
//组合逻辑与时序逻辑在同一个always块中
always@(posedge clk or negedge reset_n)
begin
if(reset_n==1’b0)
out<=1’b0;
else
begin
case(count)
2’b00 : out<= `DLY in_a;
2’b01 : out<= `DLY in_b;
2’b10 : out<= `DLY in_c;
2’b11 : out<= `DLY in_c;
default: out<= `DLY in_a;
end
end
B.always中变量赋值的唯一性
· 组合always块一定要注意敏感量列表中的触发项完整且不冗余;如果不是这样,综合的电路会与实际设计不符合,会报warning;
· 不要再多个always模块中对同一个reg型变量进行赋值;
· 更不能再同一个always中随一个变量双重赋值;
例如:
always@(posedge clk or posedge reset_n)
begin
if(reset_n==1’b0)
out<=1’b0;
else
out<= `DLY1’b1; //out 1 0
out<= `DLY1’b0;
end
· 推荐不要在一个always块里给多个变量赋值。如果将一组条件相同的变量写在一个always块中更有利于可读性的提高和功能的实现时候,可有例外情况,但请尽量多加注释,以增加可读性,并注意在组合always块中不要出现LATCH(不如对状态机的组合always块及它对条件相似的多个变量赋值);
C.always中复位的书写
复位的条件表达式及命名要和always敏感列表中的描述相统一,并且一定要使用异步复位。所有的复位必须低有效。
例如:
//
always@(posedge clk ot negedge rst_n) //
begin
if(rst_n==1’b0)
…
else
…
end
D.always的注释
要在每一个always块之前加一段注释,增加可读性和便于调试。
//cmcarry count which …
always@(posedge clk_xc or negedge rst_n)
begin
if(rst_n==1’b0)
cm_carry_cnt<=1’b0;
else
cm_carry_cnt<=#`DLY1’b1;
end
8.合理的注释
· 代码中应采用英文作详细的注释,注释量应达到代码总量的50%以上。
· 指示应该与代码一致,修改程序的时候一定要修改相应的注释;
· 注释不应重复代码已经表明的内容,而是简介的点明程序的突出特征;
· 注释应该整个一个程序的线索和关键词,它连接整个程序中分散的信息并它帮助理解程序中不能表明的部分。
9.重用化设计
层次结构与模块划分
· 层次设计的原理以简单为主――尽量避免不必要的层次;层次结构设计得好,在综合中就不需要太多的优化过程;
· 模块的划分根据层次设计来决定――模块化对于布线有很大帮助,模块化的设计中要尽量减少全局信号的使用;
· 通用的部分尽量提取出来作为一个共用模块,同时为了适应需求的更改也应提供用户定制模块入库的方式。
参数传递
· 需要传递参数的模块,在多次例化的时候统一都传递参数,不要例化同一个模块,有的传参数,有的不传。
模块划分的技巧:
将不同的时钟域分离开来;
按照不同的设计目标划分成块,分块式应在数据流方向上切分;
在同一模块中实现逻辑资源和算术资源的共享。
二.关于REVIEW
1.Review目的
发现缺陷
降低成本
提高质量
2.流程
1. 完成第一个字模块时,请提交该模块代码,进行规范检查评审。
2. Coding 期间 每两星期 提交依次代码和review报告。
Review报告主要包括内容:
· Review工作时,review的代码模块
· 参与人
· 发现的缺陷和解决情况。
Review建议:
(1) 制定review计划;(2) 每次review代码不超过500行。
ANNEX
CODESTYLE TEMPLATE
This a template of verilog code file, including file header and themain body of code in which some coding rules are demonstrated.
//********************************************************
//
// Copyright(c)2005, Hisilicon Technologies Co., Ltd
// All rights reserved
//
// IPLIB INDEX : IP lib index just as UTOPIA_B
// IPName : the top module_name of this ip, usually, issame as
the small ipclassified name just as UTOPIA
// File name : file_name of this file just as tx_fifo.v
// Module name : module_name of this file just as TX_FIFO
// Full name : complete English name of the abbreviatedmodule_name
// Author : Author
// Email : Author’s email
// Data : 2005/07/20
// Version : current version, just this: v1.0, must sameas the CVS version
//
// Abstract :
//
// Called by : Father module just as TX_PROC
//
// Modification history
// ----------------------------------------------------------------------------
// Version Data(yyyy/mm/dd) name
// Description
//
// $Log$
//
//*************************************************************
//*******************
//DEFINE(s)
//*******************
//`define UDLY 1 //Unit delay, for non-blocking assignmentsin sequential logic
//*******************
//DEFINE MODULE PORT
//*******************
module MODULE_NAME(
//INPUT
rest_n ,
clk_* ,
a_din ,
b_din ,
//OUTPUT
a_dout ,
b_dout
);
//*******************
//DEFINE PARAMETER
//*******************
//Parameter(s)
//*******************
//DEFINE INPUT
//*******************
input rst_n ; //reset, active low .
input clk_* ; //clock signal, 50M .
input [n:0] a_din ; //*****
input [k:0] b_din ; //*****
//*******************
//DEFINE OUTPUT
//*******************
output [m:0] a_dout ; //*****
output [i:0] b_dout ; //*****
//********************
//OUTPUT ATTRIBUTE
//********************
//REGS
reg [m:0] a_dout ; //*****
//WIRES
wire [i:0] b_dout ; //*****
//*********************
//INNER SIGNAL DECLARATION
//*********************
//REGS
reg [3:0] counter ; //*****
//WIRES
wire [7:0] temp1 ; //*****
//*********************
//INSTANTCE MODULE
//*********************
//**************************************************************
//instance of module MODULE_NAME_Afilename:module_name_a.v
//**************************************************************
MODULE_NAME_A U_MUDULE_NAME_A(
.A (A ),
.B (B ),
.C (C )
);
//*********************
//MAIN CORE
//*********************
//Sequential logic style
always@(posedge clk_* or negedge rest_n)
begin : SEQ_BLOCK_NAME
if(rst_n==1’b0)
counter<=4’b0;
else
begin
if (expression)
counter <= #`DLY siginal_b;
else;
end
end // SEQ_BLOCK_NAME
//Combinational logic style
always@(signal_a or signal_b)
begin:COM_BLOCK-NAME
case (expression)
item1 :begin
signal_c=*****;
end
item2 : //statement;
default ://statement;
endcase
end // COM_BLOCK_NAME
//*********************
endmodule
MACRO DEFINE TEMPLATE
//********************************************************
//
// Copyright(c)2005, Hisilicon Technologies Co., Ltd
// All rights reserved
//
// IPLIB INDEX : IP lib index just as UTOPIA_B
// IPName : the top module_name of this ip, usually, issame as
the small ipclassified name just as UTOPIA
// File name : macro.v
// Module name :
// Full name : complete English name of the abbreviatedmodule_name
// Author : Author
// Email : Author’s email
// Data : 2005/07/20
// Version : current version, just this: v1.0, must sameas the CVS version
//
// Abstract :
//
// Called by : Father module .
//
// Modification history
// ----------------------------------------------------------------------------
// Version Data(yyyy/mm/dd) name
// Description
//
// $Log$
//
//*************************************************************
//*******************
//DEFINE(s)
//*******************
`define UDLY 1 //Unit delay, for non_blocking assignmentsin sequential logic
`define DATA_WIDTH 32 //AHB data width
`define ADDR_WIDTH 32 //AHB address width