赞
踩
目录
每个IP设计人员严格遵守一个统一的良好的编码规范,在团队协作方面可以提高代码的可读性和可维护性,可以避免自己日后再次看待代码时的不理解、避免同组人员不必要的不理解、避免IP调用者的不理解、避免后期维护者的不理解,从而提高设计和维护效率;为后来的新人提供可学习的资源,提高代码的可以继承性。可以帮助系统或者软件设计人员在调试复杂系统时发现和分析IP代码所存在的问题;设计者之间可以互相利用各自拥有的IP设计资源,以便于实现IP重用的目标。在工具工作方面用以确保编写的代码能被绝大数仿真和综合工具所接受,确保Verilog RTL模块经综合所产生的门级结构与Verilog仿真器所理解的寄存器传输级的HDL代码的行为是一致的,大大减少代码在不同设计、综合和仿真平台之间移植的工作量。在成本方面,降低系统芯片设计的风险,从而降低设计成本。本规范针对于可综合逻辑部件的Verilog代码文件而编写,包括了对IP的RTL文件的建立、TOP集成文件的建立、文件头、宏定义、端口定义、TOP集成互连信号的定义、参数定义以及模块代码主体的基础规范,适用于大部分RTL编码设计情况。
团队成员或者验收人员发现任何不符合本规范的代码有义务向设计者指出不符合规范的地方,帮助提高代码的规范性。
注意:原则上本规范是普遍适用的,但可能会出现个别意外的情况,例如某工具的局限性,这可能会给本规范中个别条款的实施造成一定的困难。
例:viterbi_decoder.v文件
TOP集成即顶层集成,是将系统的多个功能模块例化在一个文件里,该文件即是TOP集成的顶层文件。集成设计文件的名字必须与TOP模块名完全一致,每个文件只能包含一个模块(module-endmodule),其构成为:设计文件名_top.扩展名。
设计文件名即为TOP模块名建议采用project name或者system name。
模块名和文件名必须具有唯一性,必须由字母和数字和下划线构成,不允许使用连续的下划线,且必须以字母开头,字母必须全部小写,禁止大小写混用,禁止使用转义字符。(注:设计文件必须和对应的测试文件区分开,测试文件用_tb后缀标明)。
例:viterbi_top.v文件
每一个可综合的Verilog RTL级电路模块(也适用于测试模块文件)必须具有规范且统一的文件头,以便于将来可用软件对模块代码进行分析处理,同时也便于建立公司内部的设计信息查询系统。文件头放在文件的最开始的地方,其中必须包含的部分有:
1 使用文件头界限标记。文件头第一行用FHEADER START标明,文件头最后一行用FHEADER END标明。标签FHEADER START和FHEADER END一定要用来定义头信息的界限。这是识别文件头的简单方法,表明该头是文件头,便于用文本工具自动的查询存档的资料。
2 文件头中必须包含文件名,用filename标明。这样有助于用文本处理工具自动的查询相关的设计文件。
3 文件头中必须包含联系方式,包括开发小组的名称、作者名字和邮箱。有助于在需要时可以找到原作者询问从设计文档无法理解的问题。
4 文件头包含发布版本历史(如V0.1)和日期。日期格式必须采用YYY-MM-DD。该信息对于顶层集成者是有用的。但本地的修改历史不应该包含其中。
5 建议文件头包含便于搜索的关键字段。该字段应该包含有关模块功能的简要说明,或是能与本模块配合运行的总线和系统名称。关键字可提供快速的搜索机制,便于自动文本处理工具搜索合适的器件。如果没有关键字,该条目应该空着。
6 文件头必须包含一段描述模块功能的说明,有助于对模块功能的理解。
7 建议文件头包含描述模块代码所使用的参数文件的名字和路径。缺省值必须都在参数文件列出,有效值域也必须标出。有助于对Verilog代码的理解和他人对相应文件的查看。
8 建议文件头包含复位策略,说明是同步复位还是异步复位,是内部复位还是外部上电复位,是硬复位还是软复位,以及该模块是否能用单个复位来调试。改善代码的可读性,突出重点和必须的综合步骤。
9 必须标明可综合能力,综合结构的能力必须以固定的YES或NO标明(如:是否该模块可被用于仿真)。
下面所示的文件头只是最小要求。在reuse issue阶段后,还可以再添加其他的文件头,另外有关版权的文件头也应该包括在文件头中。
宏定义必须放在模块内即由`define定义的宏文本声明语句必须放在模块名后(处于module和endmodule之间),这样可以避免因放在模块定义语句外的宏定义被其他层次模块的调用,从而发生无意中对某个模块外的宏定义进行重新定义的错误;如果放在了模块定义语句之外,则在相应模块结束后使用`undef取消宏定义。
例:
如果需要进行宏定义的内容很多,将宏定义放在专门定义的宏文件中,统一文件类型(filename_define.v)统一管理,在不使用相应宏定义的文件前需要对已经定义了的宏进行`undef处理。宏定义文件中包括了相应的文件头,至少需要包括的信息有:版权、公司、文件名、作者及其联系方式、功能说明、版本历史、是否有对应的`undef文件。
例:define文件和undef文件
1 模块的端口声明放在module名后的括号里,包含输入输出方向和信号类型(wire或者reg)。
2 所有端口命名必须具有唯一性,必须由字母和数字和下划线构成,不允许使用连续的下划线,且必须以字母开头,字母必须全部小写,禁止大小写混用,禁止使用转义字符。
3 单个输入信号用前缀i_表示;
4 总线输入信号用前缀iv_表示;
5 单个输出信号用前缀o_表示;
6 总线输出信号用前缀ov_表示;
7 时钟信号用_clk标明,尽量标明时钟频率,如i_clk_5m;
8 复位信号用rst标明,如果低电平复位有效用_n标明,如i_rst_n;
9 低电平有效信号用_n结尾标明,如i_rst_memory_n,i_rst_n;
10 用简洁的词或缩写表明该信号的作用,如地址信号用addr表示,复位信号用rst,时钟信号用clk;
11 声明线宽的格式必须为[n-1:0],不能用[0:n-1],标记0为LSB,n-1为MSB;
12 每行声明一个端口信号,禁止一行声明多个端口信号;
13 标明信号的来源模块或者到达模块,如i_addr_cpu2ram;
14 对每个端口做必要的注释;
15 三态输出的寄存器信号应后缀_z
16 输出信号必须被寄存
17 三态逻辑可以在顶层模块使用,子模块中避免使用三态
18 异步信号使用_a标明
19 纯延迟打拍信号使用dly作为后缀,延迟一拍表示为dly1,延迟两拍用dly2,如addr_dly1, addr_dly2
20 接口信号尽量少,接口时序尽量简单
21 更新的内容要做注释,记录修改原因,修改日期和修改人
22 与不同模块连接的端口信号放在一起,并用注释说明,且接口信号按输入、双向、输出顺序定义
23 采用单行注释,必须采用以//开头的单行注释,而以/*……*/开头的多行注释应该避免使用,这样有助于改善代码的可读性和改善代码语法分析
24 旧代码或是没用的代码必须被删掉,不能采取注释的方法
例:
1 模块的端口声明放在module名后的括号里,包含输入输出方向和信号类型(wire);
2 所有端口命名必须具有唯一性,必须由字母和数字和下划线构成,不允许使用连续的下划线,且必须以字母开头,字母必须全部小写,禁止大小写混用,禁止使用转义字符。
3 单个输入信号用前缀i_表示;
4 总线输入信号用前缀iv_表示;
5 单个输出信号用前缀o_表示;
6 总线输出信号用前缀ov_表示;
7 时钟信号用_clk标明,尽量标明时钟频率,如i_clk_5m;
8 复位信号用rst标明,如果低电平复位用_n标明,如i_rst_n;
9 低电平有效信号用_n结尾标明,如i_rst_memory_n,i_rst_n;
10 用简洁的词或缩写表明该信号的作用,如地址信号用addr表示,复位信号用rst,时钟信号用clk;
11 声明线宽的格式必须为[n-1:0],不能用[0:n-1],标记0为LSB,n-1为MSB;
12 每行一个端口信号声明,禁止多个端口信号声明在一行;
13 标明信号的来源模块或者到达模块;
14 给每个端口做必要的注释;
15 三态输出的寄存器信号应后缀_z
16 三态逻辑可以在顶层模块使用,子模块中避免使用三态
17 异步信号使用_a作为信号后缀
18 纯延迟打拍信号使用dly作为后缀,延迟一拍表示为dly1,延迟两拍用dly2
18 接口信号尽量少,接口时序尽量简单
19 更新的内容要做注释,记录修改原因,修改日期和修改人
20 与不同模块连接的端口信号放在一起,并用注释说明,且接口信号按输入、双向、输出顺序定义
21 采用单行注释,必须采用以//开头的单行注释,而以/*……*/开头的多行注释应该避免使用,这样有助于改善代码的可读性和改善代码语法分析
22 旧代码或是没用的代码必须被删掉,不能采取注释的方法
23 不要书写空的模块,即一个模块至少要有一个输入和一个输出
24 顶层PAD信号名字建议全部使用大写,比如CPU_WR代表CPU写使能管脚
25 在设计的顶层模块,将IO口、boundary scan电路的端口定义区分开
例:
TOP模块通过将各个功能子模块实例化在TOP集成文件中,各个功能子模块间存在信号的交互,功能子模块与TOP顶层端口存在信号交互。
1 各个功能子模块的实例化格式分为实例化一次和实例化多次,其格式如下所示:
实例化一次
实例化多次
2 实例化的名字与引用的模块名相同,用_u加以区分。
3 在顶层模块中,除了内部的互连和module的例化外,避免再做其他逻辑
4 各个模块间的互连线必须显式声明,且声明位置应在顶层端口声明之后,互连线声明的格式为xxx2xxx_xxx,第一部分表示数据发出方,第二部分表示数据接收方,第三部分表示数据名称,如cpu2mmu_wr表示从CPU到存储器管理单元模块的读写信号线;
5 互连线的声明中不能出现大写字母,端口和连接端口的信号尽量同名
6 在设计的顶层模块,将IO口、boundary scan电路、设计逻辑区分开
7 避免使用内部生成时钟或者门控时钟作为寄存器时钟;如果不可避免,则将时钟生成电路或者内部时钟的处理电路放到一个单独的模块,并放到设计的顶层。
8 尽量在最顶层模块处理双向总线,内部模块端口避免Inout
例:
8 参数定义
1 代码中的所有常数都应该使用参数(parameter)来定义,必须为全部大写,禁止小写或者大小写混用,允许使用下划线进行词间隔。
2 如果一个模块中的常数较多,将这些参数的定义放在一个独立的文件中,然后在设计模块中用`include宏命令将其包含。参数文件必须用如下规则命名:xxx_parameter.v。
3 如果一个模块中常数较少,可以在端口定义结束的后面定义parameter。
例1:
例2:
例3:
1 禁止对任何变量赋初始值X,对任何寄存器所赋的初始值必须是确定的
2 禁止在代码语句中加时间延迟,不允许出现如下语句:#4 out=cin。
3 禁止许使用门控时钟和门控复位。
4 禁止使用锁存器。(商用综合器可帮助执行这项规范,如使用了锁存器,综合结果会出现latch inferred)。
5 禁止在可综合的设计代码中使用`define来定义参数,应该使用parameter来定义;
6 禁止在可综合代码中使用initial、wait、fork-join、while;
7 禁止使用UDP(用户定义的原语元件);
8 禁止在可综合代码中出现逻辑反馈环路,否则会生成不可预知的逻辑电路;
9 禁止在可综合模块中使用casex,casez语句,只允许使用case和if-else语句作条件分支语句;
10 禁止在时序逻辑的设计中使用阻塞赋值=,只允许使用非阻塞赋值<=;
11 禁止在组合逻辑的设计中使用非阻塞赋值<=,只允许使用阻塞赋值=;
12 注释必须尽量靠近被注释的语句。大段的注释必须用由注释符号组成的边框//围绕。
13 建议尽可能使用高电平有效信号,不使用低电平有效信号(除某些总线、器件有特殊要求外),只有复位信号reset在特定情况下可以设置为低电平有效信号;
14 建议尽可能使用assign语句设计组合逻辑;
15 模块之间数据交换总线应该尽量用多路选择器实现,尽量不使用三态总线;
16 模块中的每个输出信号原则上必须通过寄存器输出,任何不通过寄存器输出的信号必须加以注释,注意防止出现反馈回路;
17 建议尽量合并源代码,使其简洁明了,不要试图依靠综合器的功能;
18 case语句和if-else语句必须保证完整性,即所有分支项应该完全列出,case语句应该加缺省项(default),if语句应该有对应的else项;
19 使用参数(parameter)作为可变化的常数,例如总线位宽;
20 端口和连接端口的信号尽量同名。
21 所有信号、变量均采用小写
22 低电平信号用_n结尾的表示,如:rst_memory_n,rst_n
23 声明总线宽度的语句必须用[n-1:0],而不能用[0:n-1],标记0表示LSB,标记n-1表示MSB
24 信号的声明必须一行一个,禁止多个一行,必要时在信号后添加注释
25 状态机的当前状态用current_state表示,下一个状态用next_state表示
26 状态机的初始状态用IDLE定义
27 每一行一条语句
28 always块中的语句采用空格键缩进两个字符
29 begin-end对齐,其中语句采用两个字符的空格键缩进;
30 IP内部使用偏移地址,各个IP基地址的划分在顶层单独的模块中进行处理。(访问的具体地址=基地址+偏移量地址。)
31 模块内部的实例化模块引用名与模块名相同且全部小写,用_u作为后缀,如果对同一个模块进行多次引用,在后缀上加上索引号,如_u1,_u2。
例:
32 内部模块例化采用根据端口信号名例化,禁止使用根据相对位置例化
33 信号命名不超过32个字符,在满足可读性的前提下尽量简短;
34 禁止使用不容易理解的缩写,尤其是只有一个字符的缩写作为信号的命名;
35 未连接的输出信号名以_nc结尾,有助于明白设计者意图和debug warning。(因为有时候 需要对中间输出信号进行debug)
例:
36 三态信号名以_z结尾,有助于对代码的理解,如ram_data_z
37 对信号、变量、参数的命名必须有意义,应根据对象的用途进行命名,这样有助于理解设计。
38 禁止使用Verilog和VHDL关键词用作信号名或者其他任何命名
39 在整个设计中,命名风格和拼写风格必须保持一致和连贯,便于调试。
40 所有在Verilog RTL代码中涉及到的模块和信号名必须与技术文档中的名字保持一致,确保文档和代码之间的交叉引用的正确。在Verilog RTL的注释中对信号和模块名的引用也要保持一致
41 所有信号和变量命名必须具有唯一性,必须由字母和数字和下划线构成,不允许使用连续的下划线,且必须以字母开头,字母必须全部小写,禁止大小写混用,禁止使用转义字符
42 注释每一个声明的端口,注释必要的信号和变量,注释必要的Verilog 代码block的功能即在每一个代码的功能段之前必须要有描述代码内容的功能的注释。
43 采用单行注释,必须采用以//开头的单行注释,而以/*……*/开头的多行注释应该避免使用,这样有助于改善代码的可读性和改善代码语法分析
44 旧代码或是没用的代码必须被删掉,不能采取注释的方法
45 任何实例化的单元的功能必须被注释出来,甚至是其隐藏功能,便于阅读和理解。
46 在整个代码中自由清楚的使用注释来描述代码的目的、功能、设计过程和特殊处理。一定要避免模糊的注释,增进对代码的理解
47 代码的格式必须统一(同类的代码项要对齐),当写一个代码块(诸如begin, case, if statement等等)时,首先完成代码框架,即把这个代码块的end与begin对齐,用以增进代码的可读性。
48 在代码对其中必须采用固定的2-4格缩进。不能使用TAB健,因为它在不同的文本编辑器中有不同的含义。使用空格键和空行来增加代码的可读性。
49 每一行最多只能有一个Verilog语句。不要在同一行中集中多个分号隔开的Verilog语句。(注:注释可位于与Verilog语句同一行的位置)
推荐使用:
不推荐使用:
50 每个输入输出的端口类型必须单独标明,每行只允许定义一个端口,输入在前,输出在后。有助于增进可读性,便于代码的理解和分析。
建议用以下风格:
不允许用以下风格
51 所有的内部变量必须明确的加以声明,而不允许隐含引用。内部线网、寄存器变量的声明语句必须紧跟在模块代码最上面的IO端口变量的定义后面。
例:
52 编写可综合的Verilog模块时,不允许使用根据模块层次自动命名的变量名来读取或修改某个模块中的线网及变量。用以增加可读性,便于调试。提高模块的适应性和重用性。例外:测试模块和行为模块,由于没有生成对应电路的要求,可以根据模块层次自动命名的变量名来读取或修改某个模块中的线网及变量。
53 分区时钟生成电路应位于单独的模块,位于顶层的一个独立模块中或是在与时钟应用的模块同逻辑级的模块中。这样可以简化测试策略生成,限制小模块中出现编码之外的电路。同时,这样还可以增进代码到一个不同的终端时钟应用场合的移植性。
54 建议做好时钟域的划分,独立应用的时钟应位于独立的模块中,如下图所示。在两个范围之间的同步逻辑电路最好位于一个独立的模块中。
55 建议代码的具体应用的部分和更加通用的部分应分开于两个文件夹中,通用部分用参数化的方式实现,增进对不同应用的适应性
56 建议分开数据路径逻辑与非数据路径逻辑,避免综合时的问题,简化约束和编码难度
57 分开异步逻辑与同步逻辑,避免综合时的问题,简化约束和编码难度
58 建议任何BIST(自建内测电路)逻辑写成独立的模块,便于理解、移植性和约束
59 建议控制逻辑和存储器逻辑分开成独立的模块,便于高层的存储器模块的使用和便于重新描述为不同的存储器类型
60 在引用的存储器文件外包一个wrapper文件
61 避免组合反馈回路,它不能与循环仿真器和形式化验证工具兼容
62 推荐在任何可能的情况下遵守同步设计规则。无法避免时才可使用异步设计电路
63 表达式在一定情况下必须是1bit, 以下结构中的情况必须是一个占1bit的表达式:
推荐风格:
不推荐风格:
64 reg型变量不能在两个always块中赋值,避免内部总线和仿真器依赖执行顺序
65 保持常量间的关系,即如果一个常量由另一个常量的值决定,推荐在定义时指明依赖关系。在宏文本定义算法或逻辑表达式的地方,要附上括号。增强适应性和可读性,减少代码改写的工作量
66 操作数的位宽大小必须匹配,表达式不能私自扩大或缩小它的大小
不推荐的风格:
推荐的风格:
67 推荐端口使用输入(input)和输出(output),避免使用双向(inout)类型的端口,双向执行可能导致连接问题,避免双向端口也可以简化综合和测试的输入
68 推荐使用圆括号以强制按顺序执行,较长的等式如果没有括号将依赖语言的优先选择顺序决定等式的功能,圆括号明确的规定了等式的操作顺序,清楚的表达了等式的功能,增强了可读性
69 推荐所有的矢量在端口连接时具有明确的宽度,提高代码的可读性,突出矢量端口
70 完整的组合逻辑always敏感信号列表必须包含所有的输入信号。
71 每个时序逻辑的always敏感信号列表对应一个时钟
72 不允许wait声明和#delay声明,不论是清楚还是含糊,都不能用于可综合设计
73 在可综合模块的编写中,线网和变量的初始化复位功能必须明确,不能用initial语句,因为不能生成门级网表,初始化语句会造成行为级和逻辑门级模型之间的仿真失配
74 组合逻辑必须完整的详细说明工作情况,如在何种情况下给一个变量或信号赋值。不完整的组合逻辑会导致综合工具生成锁存器的电路结构,即case的情况不全时需要加default缺省表示,if必须有完整的else。
例:由于声明是完整的,所以综合后生成的是一个纯组合电路,不会产生锁存器
75 可综合代码中循环的次数必须是有限的,无线循环的代码不能综合,也不能移植
76 端口连接时不允许用表达式,可能导致模块和综合间引起逻辑混乱,降低可读性
77 实例模块不用的输入必须由其他固定信号或者固定逻辑0或1驱动,否则可能引入未知的输入导致功能出现问题
78 不允许使用casex,因为casex在综合是不关心x和z状态,这将可能引起行为级的前后仿真不一致
79 推荐在顶层设计不引用门级逻辑,避免顶层逻辑混乱和顶层逻辑不能达到最优组合
80 不要书写空的模块,即一个模块至少要有一个输入和一个输出
81 采用小写字母定义wire、reg和input、output
82 三态输出的寄存器信号应后缀_z
83 三态逻辑可以在顶层模块使用,子模块中避免使用三态
84 采用同步设计,避免使用异步逻辑(除全局异步复位外)
85 一般不要把时钟信号作为数据信号输入
86 不要在时钟路径上添加任何buffer
87 不要采用向量的方式定义一组时钟
88 建议不要在模块内部生成时钟信号,使用PLL/DLL产生的时钟信号
89 建议采用单一的全局同步复位电路或者单一的全局异步复位电路
90 不要在复位路径上添加任何buffer,也不要使用任何门控复位信号
91 将wire/reg的定义紧随parameter之后,具有相同功能的信号集中放在一起;信号需要对齐;
92 异步信号使用_a作为信号后缀
93 纯延迟打拍信号使用dly作为后缀,延迟一拍表示为dly1,延迟两拍用dly2
94 一个Always需要配一个begin和end;always前需要有注释;信号和逻辑运算符有空格;两个always块间要隔一行;信号逻辑处理的位宽需要一致,即使+1,1的位宽定义也要和信号保持一致,需要表明位宽
95 状态机推荐使用三段式
例:
96 空格的使用:不同变量、变量与符号、变量与括号之间保留一个空格,如always @ ( …… )
97 不允许出现定义了parameter、wire、reg却没有使用的情况
98 除移位寄存器外,每个always块只对一个变量赋值,尽量避免在一个always块中出现多个变量赋值或运算
99 设计中采用基数表示法,如3’d3
100 将状态机电路和其他电路分开,便于综合和后端约束
101 将异步电路和同步电路分开,便于综合和后端约束,将相关逻辑放在一个模块内
102 如果必须要使用时钟的上升沿和时钟下降沿,则要分两个module设计
103 同步复位电路,建议在同一时钟域内使用单一的全局复位电路
104 复杂电路将组合逻辑和时序逻辑电路分成独立的always块描述
105 更新的内容要做注释,记录修改原因,修改日期和修改人
106 模块的接口信号按输入、双向、输出顺序定义
107 出于层次设计和同步设计的考虑,子模块输出信号建议用寄存器
108 为逻辑升级保留的无用端口以及信号要注释
109 在表达式内使用括号表示运算优先级
110 不允许使用常数作为if语句的条件表达式
111 不要使用===、!==等不可综合的操作符
112 在顶层模块中,时钟信号必须可见,不要在模块内部生成时钟信号,而是使用DCM/PLL产生的时钟信号
113 异步复位情况下需要异步复位信号和时钟沿做敏感量,同步复位情况下只需要时钟沿作敏感变量
/
以上内容来源于个人对工作的总结,便于日后自我查错有据可依,同时也参考了网络上对Verilog RTL的编码规范并进行了一定程度的修改和调整。如发现侵权请及时告知后会及时处理;如发现错误请帮忙指出方便修改。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。