咖啡图片
正在将巧克力泡入咖啡
ntainer" style="display: none">
文章

Verilog(2)开发规范

<摘要>

Verilog(2)开发规范

设计风格类

  • 无特殊情况建议显式指明位宽,数值较长的每四位加下划线,并注意不要让结果超出位宽的表示范围发生溢出
  • 采用小写字母定义 wire、reg、input/inout/output 以及模块名
  • 采用大写字母定义参数,参数名小于 20 个字母
  • 时钟信号应前缀 “clk”,复位信号应前缀 “rst”
  • 三态输出的寄存器信号应后缀 “_z “
  • 输入端口前缀 “ i_“,输出端口前缀 “o_”
  • 延迟打拍的变量加后缀 _r1、_r2 等
  • _d 表示延迟后的信号,_t 表示暂时存储的信号,_n 表示低有效的信号,_s 表示 slave 信号,_m 表示 master 信号
  • module 例化名用 U_xx_x 标示(多次例化用次序号 0、1、2…)
  • 使用降序排列定义向量有效位顺序,即向量的 0 索引统一为最低权重位,且不使用负数的向量域
  • 不能使用 VHDL 保留字或 verilog 保留字作为变量名
  • 顶层模块的输出信号必须被寄存(防止毛刺跑出芯片外)
  • 三态逻辑可以在顶层模块使用,子模块中避免使用三态
  • 没有未连接的端口
  • 到其它模块的接口信号,按如下顺序定义端口信号:输入、(双向)、输出
  • 建议使用 IP catalog 生成的乘法电路
  • 例化模块时使用命名端口连接而不要使用顺序端口连接,即显式写出要连接的端口名称。无需连接的端口留空而不要不写
  • 模块例化时,端口信号与连接信号隔开,并各自对齐。连接信号为向量时指明其位宽,方便阅读和调试。
  • 不要书写空的模块,即一个模块至少要有一个输入和一个输出
  • 敏感表中的表达式要用 “negedge " 或 "posedge " 的形式,而不要用 "clk" 或 " clk == 1'b1 " 的形式
  • 异步复位,高电平有效用 “If ( = 1'b1)",低电平有效用 "if ( = 1'b0)"
  • if 语句嵌套不能太多
  • 建议不使用 include 语句
  • 建议每个模块加 timescale(规避 timescale 根据编译顺序继承上一个文件可能导致的问题)
  • 代码中给出必要的注释
  • 每个文件有一个文件头,格式为文件名、设计者、日期、主要功能描述和更新记录
  • 每个文件只包含一个模块
  • 模块名和文件名保持一致
  • 定义模块时,端口类型和端口数据类型直接写在端口列表中

设计可靠性类

  • 操作数位宽不一致时建议用注释说明,避免自动扩展位宽带来隐患。有符号数扩展符号位,如果扩展出来的符号位和另一个操作数的数值部分相加了就会出问题
  • 组合 always 块中使用 case 语句必须加上 default 以规避综合出锁存器的风险。除非锁存器是刻意设计的,否则都意味着设计存在问题
  • 任何控制流语句,建议使用 beginend 关键字,编译器一般按就近原则编译,不加 beginend 关键字可能导致不安全的行为
  • 同步时序逻辑的 always block 中有且只有一个时钟信号,并且在同一个沿动作(如上升沿)
  • 同步时序逻辑的 module 中,在时钟信号的同一个沿动作
  • 采用同步设计,避免使用异步逻辑(全局异步复位除外)
  • 一般不要将时钟信号作为数据信号输入
  • 不要在时钟路径上添加任何 buffer,也不要门控时钟(会导致 EDA 把专用的时钟网络当作普通信号布线)
  • 在顶层模块中,时钟信号必须可见
  • 不要采用向量的方式定义一组时钟信号
  • 不要在模块内部生成时钟信号,使用 DLL/PLL 产生的时钟信号
  • 建议使用单一的全局同步复位电路或者单一的全部异步复位电路
  • 不要在复位路径上添加任何 buffer,也不要使用任何门控复位信号
  • 不使用 PLI 函数
  • 不使用事件变量
  • 不使用系统函数
  • 不使用用户自定义单元(UDP)
  • 不使用 disable 语句
  • 不使用 ===!=== 等不可综合的语句
  • 建议不使用 forever、repeat、while 等循环语句
  • 避免产生 latch(CPU 接口除外)
  • 组合逻辑语句块敏感表中的敏感变量必须和该块中使用的一致,不能多也不能少
  • 一个 always 语句中有且只能有一个敏感表
  • 在时序 always 块的敏感表中必须都是沿触发事件,不允许出现电平触发事件
  • 数据位宽要匹配
  • 不使用 real、time、realtime 类型,建议不使用 integer 类型
  • 移位变量必须是一个常数
  • 避免使用异步反馈环路
  • 组合 always 块中使用阻塞赋值 =,时序 always 块中使用非阻塞赋值 <=,不得混用(时序不易控制,容易得到意外结果)
  • 非阻塞型赋值不应加单位延时,尤其是对于寄存器类型的变量赋值时
  • 例化模块端口的位宽应与要连接的信号位宽保持一致,避免自动匹配可能造成的隐患
  • 时序要求、优化目标不同的信号路径需要拆分到不同的模块中。比如时序紧的关键路径和不追求速度的非关键路径就不要写在一个模块中。同一条组合路径上的代码写在同一个模块中
  • 一个 always 块中只更新一个 reg 变量;理论上来说,always 块之间是并行的,always 块内部是串行的,不过考虑到非阻塞赋值会先记录要更新的值,然后等敏感表中的条件满足时一起更新,所以这一条没有那么严格。

不常用规则类

  • 整型常量基数格式中不能有 “?”
  • 禁止使用空的时序电路块及非法的 always 结构
  • 不要在连续赋值语句中引入驱动强度和延时
  • 不要为 net、n_input、n_output、enable_gate 型变量定义驱动强度、电荷保持强度以及延时
  • 禁止使用 trireg(具有电荷保持特性连接)NET 型定义
  • 禁止使用 tri1、tri0、triand 和 trior 型的连接(net)
  • 在 RTL 级代码中不能含有 initial 结构,也不可以对任何信号进行初始化赋值,而应采用复位的方式进行初始化
  • 不要在过程块中使用 assign、deassign、force、release 等语句
  • 不要使用 wait 语句
  • 不要使用 fork-join 语句块
  • 不要为驱动类型为 supply0 和 supply1 型的连线(net)赋值
  • 设计中不使用 macro_module
  • 不要在 RTL 代码中实例门级单元,尤其是下列单元:CMOS 开关、RCMOS 开关、NMOS 开关、PMOS 开关、RNMOS 开关、RPMOS 开关、trans 双向开关、rtrans 双向开关、tranif0、tranifl、rtranif0、rtranifl、pull_gate
  • 不使用 specify 模块

参考资料

来自华为Verilog开发规范

本文由作者按照 CC BY 4.0 进行授权
/body>