文档库

最新最全的文档下载
当前位置:文档库 > VerilogHDL编码规范

VerilogHDL编码规范

VerilogHDL编码规范

目录Table of Contents

1 范围 (3)

2 综述 (3)

3 详述 (4)

3.1基本格式 (4)

3.1.1标准文件头 .......................................................................... 错误!未定义书签。

3.1.2 include (4)

3.1.3缩进格式 (4)

3.1.4注释 (4)

3.1.5保留字 (4)

3.2模块与端口 (4)

3.2.1模块命名 (4)

3.2.2模块例化 (4)

3.2.3端口定义 (4)

3.2.4输入与输出寄存 (4)

3.3信号与变量 (5)

3.3.1信号命名 (5)

3.3.2向量 (5)

3.3.3数据流向 (5)

3.3.4 Integer类型 (5)

3.3.5位宽匹配 (5)

3.3.6内部寄存 (5)

3.4时钟与复位 (5)

3.4.1时钟复位命名 (5)

3.4.2时钟可见性 (6)

3.4.3时钟不可做数据输入 (6)

3.4.4门控时钟和门控复位 (6)

3.4.5全局复位 (6)

3.4.6时钟产生 (6)

3.5设计风格 (6)

3.5.1 if与case (6)

3.5.2调试寄存器 (6)

3.5.3异步复位 (7)

3.5.4时钟事件 (7)

3.5.5顶层 (7)

3.5.6电路分级 (7)

3.5.7资源共享 (7)

3.5.8 for语句 (7)

3.5.9标准模块 (7)

3.5.10参数使用 (7)

3.5.11避免SnakePath (8)

3.6状态机 (8)

3.6.1状态机命名 (8)

3.6.2初始状态 (8)

3.6.3双进程 (8)

3.6.4状态分配 (8)

3.6.5无效状态 (8)

3.6.6状态机编码 (8)

3.7赋值 (8)

3.7.1阻塞与非阻塞赋值 (8)

3.7.2避免Latch (8)

3.7.3一个信号对应一个always (9)

3.8 always (9)

3.8.1敏感变量 (9)

3.8.2边沿触发 (9)

3.8.3单时钟(沿) (9)

3.8.4避免Latch (9)

3.8.5单(组)信号 (9)

3.9可靠性 (9)

3.9.1异步处理 (9)

3.9.2亚稳态 (9)

3.9.3异步反馈环路 (9)

3.9.4避免Lacth (10)

3.10综合 (10)

3.10.1综合器开关 (10)

3.10.2 for语句 (10)

3.10.3运算符 (10)

3.10.4移位变量 (10)

3.10.5 PLI和TASK (10)

3.10.6不可综合的语句 (10)

参考文献............................................................................................ 错误!未定义书签。

前言

VerilogHDL编码范围

1 综述

为逻辑项目开发的需要,有必要在逻辑部内制定代码规范,形成统一的编码风格,尽量减少非技术因素的影响,以确保项目开发的质量和进度。

本编码规范按照开发过程中代码编写过程划分为:基本格式、模块与端口、信号与变量、时钟与复位、设计风格、状态机、赋值、always等模块,同时对可靠性和可综合性提出了编码要求。

2 详述

2.1 基本格式

2.1.1 include

除参数和宏定义外,不要使用include来调用源文件;

有些工具对include敏感,容易出错,建议设计成模块,用模块例化的方式进行调用。

2.1.2 缩进格式

使用统一的缩进格式,若采用TAB缩进,统一设Tab键值为4个空格;

UltraEdit在菜单“Advance ->Configuration ->Edit”中设臵。

2.1.3 注释

使用必要的注释,注释量不少于20%;

注释是为了增强代码的可读性和可维护性,使用有意义的注释,要简明扼要;

在代码阶段就要添加注释,而不应该说等到代码稳定后才专门来添加。

2.1.4 保留字

代码中不能使用VHDL保留字,更不能使用verilog保留字。

2.2 模块与端口

2.2.1 模块命名

每个文件只包含一个模块,且模块名与文件名一致;

模块名大写。

2.2.2 模块例化

模块例化采用功能标识,例化名用U_XX_X标示(多次例化用次序号0、1、2...);

模块例化对信号采用基于名字(name_based)的调用而非基于顺序(order_based)的调用

2.2.3 端口定义

每行只定义1个端口,模块与其它模块连接端口顺序先按功能组划分,组内顺序为input (inout) output ;

不存在未连接的端口。

2.2.4 输入与输出寄存

建议端口上的输入与输出信号寄存一拍;

为了使输入输出时延可预测,这样做可以更容易满足是需要求。

2.3 信号与变量

2.3.1 信号命名

采用小写字母定义变量,其长度不超多26字符;

采用大写字母定义参数和宏定义,其长度不超多20字符;

对时钟反相以及其它低电平有效的信号,应该加后缀“_n”;

三态输出的寄存器应该加后缀“_z”;

信号命名必须有意义,多个单词组成的信号,单词之间用“_”隔离。

2.3.2 向量

使用降序排列定义向量有效位顺序,其最低位是0;

2.3.3 数据流向

建议一级模块间的信号命名应该包含流向信息。

如A模块输出给B模块的信号,命名为A_B_signal;B模块输出给A模块的信号命名为B_A_signal。

2.3.4 Integer类型

建议不使用integer类型。

-有些综合工具支持的不好,而且不方便移植。

2.3.5 位宽匹配

数据位宽要匹配。

-否则容易造成条件判断和例化时的错误。

2.3.6 内部寄存

建议内部寄存信号采用“信号名_寄存拍数d”的命名方式。

比如datain_1d表示对datain寄存了1拍。

2.4 时钟与复位

2.4.1 时钟复位命名

时钟信号应前缀“clk”,复位信号应前缀“rst”;

同一源驱动的时钟使用同一个名称,时钟命名方式clk频率_d相位;

不要采用向量的方式定义一组时钟信号。

2.4.2 时钟可见性

在顶层模块中,时钟信号必须可见。

2.4.3 时钟不可做数据输入

一般不要将时钟信号作为数据信号输入。

仅在时钟检测时可以使用;

如果将时钟信号作为数据输入,会导致时钟路径分析出错。

2.4.4 门控时钟和门控复位

不要在时钟路径上添加任何buffer,也不要使用门控时钟;

会使时钟树变得复杂,增大clock_skew。使用门控时钟不利于移植,可能引入毛刺,对时序带

来问题,同时对扫描链的形成带来问题。

不要在复位路径上添加任何buffer,也不要使用任何门控复位信号。

门控信号容易产生毛刺,引起系统异常复位。

2.4.5 全局复位

建议使用单一的全局同步复位电路或者单一的全部异步复位电路,逻辑内部复位信号统一采用高

电平。

建议异步复位信号在连到模块之前用相同时钟域的时钟寄存一拍;

对异步复位进行同步化,避免产生不能同步撤离的问题。

2.4.6 时钟产生

若要产生时钟信号,必须要使用DCM/PLL产生的时钟信号,不要在模块内部直接产生时钟信号;

内部时钟产生模块是一个独立的一级子模块。

2.5 设计风格

2.5.1 if与case

if语句嵌套不能太多,建议小于5级。

多级的if-else会综合成多级的优先编码器的串接,嵌套级数越多,速度会越低。级数多时建议

用case语句。

2.5.2 调试寄存器

建议在资源允许的情况下,内部增加调试寄存器,存储关键信号和状态,以及相应的计数器。供调试用。

由于逻辑编译的时间太长,预先加入一些关键信号的调试寄存器方便后期的上板调试和问题定

位。

2.5.3 异步复位

异步复位,高电平有效用"If( == 1'b1)",低电平有效用"if( == 1'b0)“。

2.5.4 时钟事件

时钟事件的表达式要用“negedge ”或“posedge ”的形式。

2.5.5 顶层

顶层没有其它逻辑(三态逻辑除外)。

三态逻辑只允许在顶层使用,在顶层应该完成输入输出的转换。

2.5.6 电路分级

注意电路分级,尽量让电路并行执行,降低执行时间。

如Z=A+B+C+D写成Z=(A+B)+(C+D)。

2.5.7 资源共享

只有在同一个模块的同一段always块中的代码才可能共享资源,综合器根据约束决定是否实现资源共享。

如:always @ (...)

if (..) Do = A + B;

else Do = C + D;

可能只会生成一个加法器。

2.5.8 for语句

For语句在综合时会占大量资源,尽量不要使用,如果必须使用,则与for变量无关的语句不要放在for循环之内以减少Area。

2.5.9 标准模块

建议使用coregen或者megawizard生成的标准模块电路,代码中直接例化使用。如RAM等。

2.5.10 参数使用

在可能的情况下,尽量使用宏定义和参数,以提高可重用和可移植性。

2.5.11 避免SnakePath

在代码中,注意避免一段组合逻辑分布在多个Module中,因为综合器往往不能跨模块进行优化。

尽量将组合逻辑放在同一个模块中,且模块的输出为寄存器输出,模块之间不要增加附加逻辑。

2.6 状态机

2.6.1 状态机命名

状态机状态信号命名:状态名_cur 、状态名_next。

2.6.2 初始状态

状态机上电复位后必须有初始状态和默认状态,否则状态机不会跳转。

2.6.3 双进程

状态机使用双进程描述,将状态转移单独写成一个进程,将状态的操作和判断单独写成一个进程。

2.6.4 状态分配

状态机状态必须用parameter 分配好状态。

2.6.5 无效状态

无效状态能够自动转为有效状态。

可有效的防止状态机跑飞。

需要给状态机跳转判断的case加上default出口。

2.6.6 状态机编码

建议状态机编码尽量采用gray或者one_hot。

sequential、gray-code编码使用最少的触发器,较多的组合逻辑。而one-hot编码反之。由于CPLD更

多的提供组合逻辑资源,而FPGA更多的提供触发器资源,所以CPLD多使用gray-cod e,而FPGA多使

用one-hot编码。另一方面,对于小型设计使用gray-code和binary编码更有效,而大型状态机使用

one-hot更高效。

2.7 赋值

2.7.1 阻塞与非阻塞赋值

时序逻辑语句块中统一使用非阻塞型赋值,组合逻辑语句块中使用阻塞型赋值;

2.7.2 避免Latch

组合逻辑中,不允许给自己赋值。

否则将会引入Latch。

2.7.3 一个信号对应一个always

除三态信号外,不允许同一个信号在多个always中被同时赋值。

2.8 always

2.8.1 敏感变量

组合逻辑语句块敏感表中的敏感变量必须和该块中使用的相一致,不能多也不能少。

RTL级仿真时是基于敏感变量的,而综合时是基于输入的,因此敏感变量不全会导致RTL级仿真错误,而综合结果一般是正确的。

2.8.2 边沿触发

在时序always块的敏感事件列表中必须都是沿触发事件,不允许出现电平触发事件。

2.8.3 单时钟(沿)

同步时序逻辑的always block中有且只有一个时钟信号,并且在同一个沿动作(如上升沿)。

2.8.4 避免Latch

在没有时钟的always的赋值语句中,所有信号在else里都必须有赋值,分支不全的case的default 里也必须有赋值。

2.8.5 单(组)信号

一个always中,只能对一个或者一组相关的信号进行赋值。

2.9 可靠性

2.9.1 异步处理

避免同步设计使用异步逻辑(全局异步复位除外)。如果不可避免的要是用异步逻辑,那么:

尽可能使用异步FIFO进行时钟域隔离;

一个时钟域的信号进入另外一个时钟域时,至少保证用本时钟域的时钟打一拍再使用。

2.9.2 亚稳态

内部异步采样,为了防止出现亚稳态。所有信号必须在本时钟域内至少寄存一拍再判断。

可以有效的防止亚稳态的传播,推荐寄存两拍以后再判断。

2.9.3 异步反馈环路

避免使用异步反馈环路。

容易受毛刺影响,降低系统稳定性。

2.9.4 避免Lacth

组合逻辑一定避免无意引入Latch。

latch的生成会极大的增加后端设计的困难,j降低系统时序,同时也降低了系统的可测性,因为

对于latch,必须加一些测试逻辑才能够测试,有的甚至就无法测试。

2.10 综合

2.10.1 综合器开关

避免在代码中使用综合器开关。

这样是为了防止综合前后的仿真结果不一样,同时降低对综合器的依赖,增强代码移植性。2.10.2 for语句

for语句循环变量的取值边界必须为常数,否则不能被综合。

2.10.3 运算符

不要使用===、!===等不可综合的运算符。

2.10.4 移位变量

移位变量必须是一个常数,否则不能被综合。

2.10.5 PLI和TASK

PLI函数和TASK不能被综合器支持,应避免使用。

2.10.6 不可综合的语句

避免使用用于验证或者建模的不能被综合器支持的语句。这些语句包括:

initial

assign-deassign、force-release

fork-join

forever、repeat、while

wait

real、time、realtime

tri1、tri0、triand、trior、trireg

macro_module

specify

cmos、rcmos、nmos、pmos、rnmos、rpmos、trans、rtrans、tranif0、tranif1、rtranif0、rtranif1、pull_gate

net、n_input、n_output、enable_gate