命名规则
1 代码中尽量避免使用数字,较多的采用宏定义,全部宏都在头文件中定义。
2. 每行代码文字数量都控制在80以内,行的缩进使用Tab
3. 如果你只使用verilog,那么建议用匈牙利命名法。
匈牙利命名法:开头字母用变量类型的缩写,其余部分用变量的英文或英文的缩写,要求单词第一个字母大写
输入输出:
1比特的输入端口以i开头,1比特的输出端口以o开头,1比特的双向端口以io开头。
多比特的输入端口以iv开头,多比特的输出端口以ov开头,多比特的双向端口以iov开头。要跟邻近的端口名对齐。(v是vector的意思)
module time_ctrl (
input iAdc_clk,
input iAdc_por,
output oS_h,
output oC_on
);
变量:
一比特的reg型变量以r开头,1比特wire变量以w开头。
多比特的reg型变量以rv开头,多比特的wire型变量以wv开头。要跟邻近的变量名对齐。
reg变量都要赋初值’b0,包括端口名(如 output reg oData='b0)。
- 变量名其余部分使用英文小写字母、数字以及下划线“”进行命名,为了明确内部控制信号的极性,负逻辑信号线的名称以下划线“”结尾,宏使用英文大写字母,英文小写字母,数字以及下划线“_”进行命名
- 信号名除单词首字母以外一律小写,参数以及宏定义一律大写。
- 头文件中为了防止同一个文件被多次包含,包含文件的代码全部写作`ifndef中。
- 尽可能使用assign语句设计组合逻辑
- 模块中的每个输出信号原则上必须通过寄存器输出。任何不通过寄存器输出的信号必须加以注释,注意防止出现反馈回路。
- case语句和if else语句必须保证其完整性,即所有分支项应该完全列出,case语句应该加缺省项(default),if语句应该有对应的else项
- 使用参数(parameter)作为可变化的常数,例如总线的位宽。
- 端口声明的顺序--在保证先输入再输出的基础上按如下顺序clocks,resets,control signals,address bus,data bus
- 端口和连接端口的信号尽量同名
- 注释应尽量靠近被注释的语句。大段的注释必须用由注释符号组成的边框/////////////// 围绕。
- 代码中的所有常数都应该使用参数(parameter),将这些参数的定义放在一个独立的文件中
- 模块名跟文件名相同,都用小写,顶层文件要加上_top后缀。而testbench文件则加上_tb后缀。
- 声明总线宽度的语句必须用 [n:0], 而不能用 [0:n],标记0表示LSB, 标记n表示MSB
- 输入/输出端口和信号的声明必须每个信号一行,然后组合起来,必要时在端口信号后添加注释。
- 表示组合逻辑的always块的电平敏感列表,必须每个变量一行文件命名
- 每个模块必须用一个文件表示。在一个文件中不允许编写一个以上的模块。
- 文件名必须以下列方式构成:<设计单元名>:[<文件类型>]。<扩展名>。
其中,<设计单元名>是设计的单元名。
[<文件类型>] 标明文件类型(可选):
_task文件由任务构成,
_func文件由函数构成,
_parameter 文件由参数构成,
_defines文件由宏文本构成。
_disc文件是规则文件
_connect 文件是连接规则和连接模块文件
表示是个Verilog文件 .v是Verilog文件 .va是Verilog-AMS文件
原因:从文件名就可以知道设计代码的构成,简化了代码维护人员对设计结构和文件内容的理解
例子:spooler.v是模块spooler的代码。spooler_task.v 是包含spooler模块所用任务的文件。
- Verilog代码中模块的命名要必须与文件名字完全一致(扩展名除外)
所有在Verilog RTL代码中涉及到的模块和信号名必须与技术文档中的名字保持一致。在Verilog RTL的注释中对信号和模块名的引用也要保持一致。
原因:确保文挡和代码之间的交叉引用的正确。 - 对低电平有效信号进行命名时,必须使用“_n” 作为名字的后缀 ,其他情况一律不允许使用“_n”作为名字的后缀。
当且仅当为低电平有效信号命名时,才允许使用“_n”为后缀的信号名。
原因:有意义的、连贯一致的命名风格有助于对设计的理解。
例子:enable_data_n, reset_n - 建议引用的实例化模块名与实例名相同,用索引号区别这两者
引用的实例化模块的命名应该与被引用的实例名相同,用索引号区别这两者。一个实例模块的多次实例化引用模块用整数索引加以区分。
原因:可以增进可读性、减少模糊性
例子:blockx U_blockx_1 (…);
blockx U_blockx_2 (…);
代码风格
-
一行一个端口定义
每个输入/输出信号的端口类型必须单独标明,这就是说每行只允许定义一个端口,每个线网变量对应一个方向(输入/输出)。
原因:增进可读性,便于代码的理解和分析。
强烈建议端口声明保持与模块的端口列表同样的顺序。
原因:增进可读性。 -
明确地声明内部变量
所有的内部变量必须明确地加以声明,而不允许隐含引用。
原因:尽管 Verilog 仿真器和综合器都能够处理隐含声明的线网类型的变量,但是所有的内部变量都必须明确地声明以避免混乱。 -
声明所有的内部变量于同一个段中
内部线网变量的声明语句必须紧跟在模块代码最上面的I/O端口变量的定义后面。
原因:便于对代码的理解。
例外:自动生成的代码。 -
if、while语句中必须指明条件中的值,不允许写成if(wSwitch)begin。
如:if (wSwitch==1’b1) -
每个文件的开头,都要加注释头,并说明该文件的作用。
//======================================================================
// Filename : :sdram_top.v
// Created On : :2016-08-02 18:25:37
// Last Modified : :2016-08-09 20:44:19
// vertion : :1
// Author : :LeaderHuang
// Description : :sdram controller top design file
// using qsys sdram controller ip core
//
//======================================================================
-
不依赖verilog默认的优先级,每个运算都加括号。
assign p=(a|b)&(c^(~d)); -
case语句下的分支要排列整齐,begin放在条件后,end对齐条件判断。
always@(posedge clk)begin
if(en==1’b1)begin
case(rvNextState)
IDLE :begin rClr<=1’b0;end
CLEAR :begin rClr<=1’b1;end
default :begin rClr<=1’b0;end
endcase
end
end
模块的划分及可重用性
-
分开状态机
建议FSMs变成独立的模块。把状态机分成两个过程:一个组合逻辑,一个时序逻辑。
原因:避免综合时的问题,简化约束和编码难度。 -
分开控制逻辑和存储器
建议控制逻辑和存储器逻辑分成独立的模块
原因:便于高层的存储器模块的使用和便于重新描述为不同的存储器类型。
建模规则 -
使用同步设计规则
推荐在任何可能的情况下遵守同步设计规则。无法避免时才可使用异步设计电路。
原因:目前还没有完全支持异步设计的设计工具。
例外:不需要综合的行为模块(如,总线功能模块,总线监视器和行为级模型)可以使用异步设计。 -
使用异步复位同步释放规则
异步复位结构简单,且单元库一般只有异步复位。缺点是容易产生毛刺,时序设计要注意。电路设计中复位要全部从顶层给出,不能内部产生。
编码方法概要
- 组合逻辑必须完整的详细说明(如,在任何情况下给一个变量或信号赋值)
原因:若组合逻辑的说明不完整,则综合工具会根据语义生成具有寄存器的电路构造。
例子:由于声明是完整的,所以综合后生成的是一个纯组合电路,不会产生寄存器 。
always @(signal_names)begin
case (signal_names)
3’b000,
3’b001 : output = 4’b0000;
3’b010 : output = 4’b1010;
3’b011,
3’b100,
3’b101 : output = 4’b0101;
3’b110,
3’b111 : output = 4’b0001;
Endcase
end