FPGA基础 -- Verilog 锁存器简介

发布于:2025-06-19 ⋅ 阅读:(14) ⋅ 点赞:(0)

由浅入深地讲解 Verilog 中的锁存器(Latch)**,包括:

  1. 什么是锁存器(定义与作用)
  2. 锁存器的分类(透明锁存器 vs 边沿触发器)
  3. Verilog 中锁存器的建模方式
  4. 锁存器与触发器的区别
  5. 锁存器的时序特性与设计陷阱
  6. 实际应用与避免锁存器的最佳实践
  7. 综合工具识别锁存器的方式与调试技巧

一、什么是锁存器(Latch)?

锁存器是一种电平敏感的时序逻辑单元,用于在特定控制信号(如 enableclk 为高电平)时锁存输入数据,否则保持原状态。

🔧 本质上,它在控制信号有效时“透明”地传输数据”,无效时“记住上次的值”

锁存器的简要逻辑图:

         +-----------+
D ------>|           |
         |  Latch    |----> Q
EN ----->| (Enable)  |
         +-----------+

二、锁存器的分类

类型 控制信号敏感方式 特点
透明锁存器(Transparent Latch) 电平敏感(高电平或低电平) 开启时透传,关闭时保持
边沿触发器(Flip-Flop) 上升/下降沿敏感 只在边沿更新值(由两个锁存器组合)

注意:触发器(如 D Flip-Flop)是由两个互补使能的锁存器串联形成的结构(主从结构),是锁存器的扩展版本。


三、Verilog 中锁存器的建模方式

锁存器一般是always 块中使用电平敏感的敏感列表并缺少完整的 else 分支时自动生成。

1. 透明锁存器建模示例

module latch_example (
    input  wire en,
    input  wire d,
    output reg  q
);

always @(en or d) begin
    if (en)
        q = d;
    // 没有 else,q 会自动保持原值,综合器推断 latch
end

endmodule

❗ 这是经典 latch 写法if 条件成立赋新值,条件不成立时,q 保持原值,导致 latch 自动生成。


2. 如果不小心写出 latch?

如下代码也会综合出 latch,因为 q 只有在某个条件下才赋值:

always @(a or b or sel) begin
    if (sel)
        q = a; // 没有对 sel==0 情况赋值 => latch!
end

为避免这种情况,建议始终覆盖所有逻辑分支,如:

always @(a or b or sel) begin
    if (sel)
        q = a;
    else
        q = b;  // 所有分支覆盖 => 组合逻辑
end

四、锁存器与触发器的区别

特性 锁存器(Latch) 触发器(Flip-Flop)
敏感性 电平敏感 边沿敏感
控制方式 Enable 信号 Clock 上升/下降沿
透明性 是(在 EN 有效时)
建模方法 电平触发 always 边沿触发 always_ff
延迟控制 容易受组合逻辑影响 较稳定,边沿采样
用途 短暂锁存/流水线优化 寄存器、状态保持

五、锁存器的时序特性与设计陷阱

时序特性:

  • 透明期内输入变化会直接影响输出,很容易引入毛刺或竞争;
  • 在综合中,如果 Latch 与组合逻辑交织使用,可能会出现 逻辑冒险(hazard)
  • Hold time 要求更严格,不易进行 STA(静态时序分析);

常见设计陷阱:

错误用法 问题原因
没有覆盖所有 if/else 分支 导致 latch 被综合
在组合逻辑路径中插入 latch 不易分析,逻辑难以收敛
Latch 控制信号由组合逻辑生成 产生不定延迟与冒险

六、实际应用场景与如何规避 latch?

✅ 可控使用的场景(明确要用 latch):

  • 异步数据采样或保持
  • 功耗优化(某些低速模块)
  • 状态保持器(FSM 中稀有)

❌ 一般应规避 latch:

在主流 FPGA 项目中,推荐只使用触发器,不主动写 latch,原因包括:

  • 综合工具难以时序约束 latch;
  • ILA 等调试工具难以观测 latch 的状态;
  • latch 可能引入冒险、毛刺、竞争,造成 bug;

七、Vivado/Quartus/Lattice 中 latch 检查方式

✅ Vivado 示例:

  1. 编译后,在 Messages -> Synthesized Design -> Latches Inferred 会列出 latch;

  2. 可通过约束文件添加:

    set_property HD.CLK_SRC {NONE} [get_cells -hierarchical -filter {CELLTYPE == latch}]
    

    来阻止 latch 合成;

✅ 建议工具策略:

  • 使用 always_ff @(posedge clk)(SystemVerilog)
  • 在组合逻辑使用 always @(*)全分支赋值

总结

知识点 说明
锁存器本质 电平敏感,控制信号有效时透明,反之保持
建模方式 条件赋值但未赋全分支时会被综合出 latch
与触发器区别 触发器是边沿敏感,锁存器是电平敏感
风险 容易引起时序问题、冒险、毛刺
建议 组合逻辑必须全分支赋值,时序逻辑建议统一用触发器

网站公告

今日签到

点亮在社区的每一天
去签到