Verilog编码规范

Verilog编码规范

​ 本文为自己研究实践与翻阅资料比如华为规范书等所得,主要关于编码问题以及综合电路映射问题,规范自己写出复用性更好、综合性能更好、便于仿真的代码和电路。



第一部分 Verilog RTL规范

1 、Module

  1. 顶层模块应该只是模块间的互联,尽量避免再做逻辑。如不能再出现对reg变量赋值等,这样做的目是为了更有效的综合。因为在顶层模块中出现中间逻辑,Synopsys 的design compiler 就不能把子模块中的逻辑综合到最优。

  2. 每一个模块应在开始处注明文件名功能描述设计者设计时间及版权信息等,下面为sublime模版

    // -------------------------------------------------------------------------
    // Copyright (c) 2014-{YEAR} All rights reserved
    // -------------------------------------------------------------------------
    // Author 		: HiDark 1173296519@qq.com
    // File   		: {FILE}
    // Create 		: {DATE} {TIME}
    // Description	: 
    // Editor 		: tab size ({TABS})
    // -------------------------------------------------------------------------
    module mymodule
    (
        // Inputs
        input          clk,
        input          rst_n,
        // Outputs
    );
    //-----------------------------------------------------------------
    // A
    //-----------------------------------------------------------------
    endmodule
    
  3. 模块输出寄存器化

    对所有模块的输出加以寄存如图1使得输出的驱动强度和输入的延迟可以预测从而使得模块的综合过程更简单.

    输出驱动的强度都等于平均的触发器驱动强度

image-20231219223824965

2、选择器(if-else、case、?:)

  1. 优先级问题
  • if-else和?:都是生成优先级,多个2选1嵌套在一起,如下图左边。但是if 嵌套过多会导致速度很慢,路径延时很大,因此一般条件较少时适用,if else结构下最终综合的电路速度较慢,面积小。case综合为 n选1 mux电路,如下图右边。没有优先级,因此延时小,但占用面积较大。

    image-20231219224141951

  • 通常使用case 语句要比if语句快。优先编码器的结构仅在信号的到达有先后时使用,优先级可以用来优化关键路径的时序。条件赋值语句也能综合成多路复用器,而case 语句仿真要比条件赋值语句快。

  1. 资源共享问题
  • 条件算子中不存在 资源共享 ,如下,综合必须使用两个加法器;
z = (cond) ? (a + b) : (c + d);
  • 而等效的条件if-then-else语句则可以资源共享 如下只要加法器的输入端复用,就可以实现加法器的共享,使用一个加法器实现。
if (Cond)
 z = a + b;
 else
 z = c + d;

3、宏参数Macro

  • 把 ``define` 都放在一个单独文件
  • parameterlocalparam

4、时钟

  1. 不要用为了起方便名字对时钟assign,否则可能会在综合时插入buf导致时序错误(吴斌老师讲的,但是没有试过)
  2. 避免在RTL代码中使用门控时钟(Gated clock)。不利于移植,可能引起毛刺带来时序问题,同时对扫描链的形成带来问题。门控钟在低功耗设计中使用,并且借助工具生成。
  3. 避免在RTL级手工实例化时钟Buffer,后端物理设计才考虑

5、复位

  1. 同步复位。 由于大多数触发器都没有同步复位端,因此同步复位会多引入一级逻辑,路径延时增大。而且同步复位依赖时钟,如果复位时间少一个时钟或时钟未使能、未工作就会失效。

  2. 异步复位。优点是不依赖时钟,但容易引入毛刺,因此为消除异步复位的缺陷,复位电路往往会采用“异步复位、同步释放”的设计方法,引入两级寄存器

    复位时与异步复位相同,都是立刻复位,在释放时经过两级触发器,确保不会产生由复位信号释放产生的亚稳态。典型代码如下

    // 引自 https://zhuanlan.zhihu.com/p/405938699?utm_id=0
    module areset_srelease(
        input       rstn,  //异步复位信号
        input       clk,   //时钟
        input       din,   //输入数据
        output reg  dout   //输出数据
        );  
        reg   rstn_r1, rstn_r2;
        always @ (posedge clk or negedge rstn) begin
            if (!rstn) begin
                rstn_r1 <= 1'b0;     //异步复位
                rstn_r2 <= 1'b0;  
            end
            else begin
                rstn_r1 <= 1'b1;     //同步释放
                rstn_r2 <= rstn_r1;  //同步打拍,时序差可以多延迟几拍
            end
        end  
        //使用 rstn_r2 做同步复位,复位信号可以加到敏感列表中
        always @ (posedge clk or negedge rstn_r2) begin
            if (!rstn_r2) dout <= 1'b0; //同步复位
            else          dout <= din;
        end
    endmodule
    

    被表述为以下综合电路

    image-20231220221645995

    时序图:

    image-20231220223941227

    Wavedrom 代码

    { signal: [
    { name: "clk",  wave: "P.............................",period: 2},
    { name: "rstn",  wave: "1..0.1......................."},
    { name: "din", wave: "1...........",},
    { name: "rstn_r1",  wave: "1..0..1....................."},
    { name: "rstn_r2",  wave: "1..0....1....................."},
    { name: "dout", wave: "1..0......1.",},
    ],  config: { hscale: 1.5 }}
    
  3. 取消复位。

    由于复位会引入逻辑,消耗面积和速度。因此在复位不影响功能的正确实现下,数据流或流水线级可取消复位,提高性能.

第二部分 设计方法规范

1、设计优先

​ 由于工艺越来越先进,面积要求越来越不明显,速度逐渐成为设计的首要要求。

2、可复用性编码

2.1 命名原则
  • 为开发指定命名,并以文档形式记录,应用到全局中

  • 变量名、端口名和信号名小写

  • 常量和用户定义类型大写

  • 用有意义的名字,如地址ram_addr而不用ra

  • 来自同一驱动器源的所有时钟信号使用相同名字(吴斌老师强调过)

  • 对于低电平有效信号,加后缀_n,如rst_n

  • 数字代表英文字母,例如 2 代表 to, 4 代表 for, 简化信号名。

  • 尽可能用下表命名

    约定用途
    _r寄存器输出,延迟打拍用r1、r2
    _a异步信号
    _pn在第n步{phase}使用的信号
    _next锁存前信号
    _z三态

第三部分 Verilog仿真规范

  • testbench赋值用 <=

​ 如果用=,并且是@(posedge clk) a = 1;实际结果会是立刻变化,即上升沿之前变化。

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Verilog 是一种硬件描述语言,用于描述数字系统的行为和结构。编写 Verilog 代码时,遵循一些编码规范可以提高代码的可读性和可维护性。以下是一些常见的 Verilog 编码规范: 1. 缩进:使用适当的缩进来显示代码的层次结构。通常使用四个空格或一个制表符进行缩进。 2. 注释:使用注释来解释代码的功能、目的和实现细节。注释应该清晰明了,帮助他人理解代码。 3. 命名规范:选择有意义的变量和模块名称,使用驼峰命名法或下划线分隔符命名法。避免使用单个字符作为变量名称。 4. 代码布局:按照从顶层到底层的顺序组织代码。首先定义模块接口,然后是内部信号和变量声明,最后是具体的功能实现。 5. 模块接口:按照输入、输出和内部信号的顺序声明模块接口。在每个端口之间使用逗号分隔。 6. 关键字和运算符:将关键字和运算符与周围的文本用空格分隔开,以增加代码的可读性。 7. 括号使用:在括号内部和外部留有适当的空格,以增加代码的可读性。避免过多或过少使用括号。 8. 代码长度:避免编写过长的代码行,通常建议每行不超过80个字符。 9. 代码复用:使用模块化的方法编写代码,避免重复的功能实现。可以将常用的逻辑封装为子模块,以便在多个地方复用。 10. 代码风格一致性:在一个项目或团队中保持代码风格一致性,以便于代码的理解和维护。 以上是一些常见的 Verilog 编码规范,希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值