latch相关知识
参考链接:
latch介绍
Latch 和 Flip-Flop 的区别:
- Flip-flop 是边沿触发的(edge-triggered),在时钟上升沿或下降沿采样数据
- Latch 是电平敏感的(level-sensitive),在时钟为高(或低)电平期间透明传输数据,时钟无效时锁存
产生latch的写法:always块来描述 if 没有 else,或 case 没有 default,产生latch的典型写法如下
1 | always @(*) |
为什么不推荐latch
主要有两个原因,一个是锁存器对毛刺不敏感,很容易造成毛刺的传播;第二个是STA相比Flip-Flop更加复杂
note
大多数数字设计规范不鼓励手写 latch,因为静态时序分析更复杂,且容易因为编码疏忽意外生成latch
为什么锁存器的静态时序分析更加复杂,主要有下面原因
-
首先对于Flip-Flop的STA,简单明确,我们需要满足setup check和hold check,起点和终点都是基于时钟边沿来分析的;对于latch来说,STA 工具不能像 flip-flop 那样只对一个沿做检查,而要分析数据落在窗口内的哪个位置,这直接影响后级还剩多少时间可用
-
Flip-flop 的 setup check 永远是"launch edge 到下一个 capture edge",没有歧义;Latch 可能出现是当前周期透明窗口或者下个周期透明窗口问题等。具体可以查看timing borrow的两个应用。
-
一级借了时间,下一级可用时间就少了;下一级如果也需要借,再影响下下级。STA 工具必须沿着整条路径链式传播这个借用关系,不能逐级独立分析
-
Flip-flop 的 hold check 通常只看同一个沿(或相邻沿),很直观,但是latch的 hold check 必须确保数据不会在透明期内穿透到不该到的地方
latch的使用场景
虽然不推荐latch,但是在实际上latch也有相对应的使用场景
时钟门控
问题:想在不需要时关掉时钟以省功耗,但 enable 信号是随机时刻变化的,如果直接和时钟做 AND,enable 在时钟高电平期间变化会产生 glitch(毛刺),导致下游 flip-flop 误触发
解决方案: 用一个 latch 先把 enable 锁存,保证它只在安全时刻(时钟低电平期间)更新,这是针对时钟上升沿触发的时钟域

!!!important
Latch 在 CLK=0 时透明(采样 EN),CLK=1 时锁存(保持 EN_latched 不变)。这样 EN 无论什么时候跳变,GCLK 都不会出现毛刺
verilog的行为模型:
1 | always @(*)begin |
Time Borrowing
三级触发器例子
首先介绍一下时间借用的概念:
假设时钟周期为10个时间单位,占空比为50%,时钟波形如下所示:

同时,考虑一个简单的三级触发器电路:

info
为了简化分析,假设所有触发器的建立时间,保持时间都是0,时钟偏斜和时钟延迟也是0。 从0时刻从F1发出的数据,必须在10时刻之前到达F2才能被正确捕获。同理,从F2发出的数据也有10个时间单位传输到F3,并在下一个时钟边沿被采样。
现在,将中间的触发器F2替换为一个由同一时钟驱动的锁存器L2

从 F1 到 L2 的路径分析:
如果数据在 10 时刻之前到达锁存器输入端,它会像在触发器前一样等待。但关键区别在于,如果数据在 10 时刻之后到达呢?锁存器 L2 在 10 到 15 的时间段内是“透明”的。因此,只要数据在 15 时刻之前到达,L2 仍然能够捕获并使用它。
例如,若数据在 12 时刻到达 L2,这意味着锁存器为这条路径提供了 2 个时间单位的额外裕量(相较于触发器)。在这个例子中,L2 能提供的最大优势(即最大可借用时间)是 5 个时间单位(透明窗口的宽度)。
从 L2 到 F3 的路径分析
数据在 12 时刻从 L2 输出,并需要在 20 时刻被 F3 采样。因此,留给这条路径的时间只有 8 个时间单位(20 - 12)
info
时间借用的本质:在全触发器的电路中,F2 到 F3 的路径本有 10 个时间单位。但在当前电路中,它少了 2 个时间单位。这 2 个时间单位被前一级路径(F1 到 L2)“借用”了
关键点总结:
馈入锁存器的路径可以从后续路径借用时间(最大不超过锁存器的透明窗口),实际借用的时间量是路径满足时序的最小值(受限于最大可借用时间)。在上面这个例子中,最大可借用时间量是5个时间单位,在实际中借用了两个时间单位。
建立时间分析
对于在 0 时刻由 F1 发出的数据,L2 在 0 到 5 的时间窗口内是开放的,可以捕获数据。
STA 工具会将 0 时刻视为 L2 的捕获沿,并附带一个 5 个时间单位的借用容量。同时,从 L2 到 F3 的路径分析为:在 0 时刻发送,在 10 时刻于 F3 处捕获。因此,整体从 L1 到 F3 的路径总时间预算为 10,其中最多 5 个单位可用于 L2 之前的部分,剩余部分用于 L2 之后。
保持时间分析
保持时间分析要确保前一个周期的数据不会被新数据干扰。F1 在 0 时刻发送的数据,可能在 0 到 5 期间被 L2 捕获。
那么,F1 在下一个周期(10 时刻)发送的数据呢?如果它在 5 时刻之前到达 L2,就会干扰 0 时刻的数据。因此,STA 工具会针对 F1 在 10 时刻发送的数据和 L2 在 5 时刻的捕获沿,执行一次保持时间检查,确保新数据不会过早到达。
CRPR介绍
CRPR(Clock Reconvergence Pessmism Removal),也叫CPPR(Clock Path Pessimism Removal),是时序分析中消除时钟路径上虚假悲观度的技术。
问题来源:
在OCV分析中,同一条时钟路径在作为 launch clock 时取 max/late delay,作为 capture clock 时取 min/early delay。当 launch 和 capture clock 有公共路径段时,同一段物理连线被同时假设为又慢又快,这在物理上不可能发生,产生了虚假的悲观度。
举个例子,假设有下面这个例子:clk_root连接到两个FF,作为工作时钟,但是UFF0是launch path,UFF1是capture path
1 | CLK_root |
在进行ocv分析时:
- BUF_A在launch path上取max_delay,0.5ns
- BUF_A在capture path上取min_delay,0.3ns
- 差值 0.2ns 就是虚假悲观度 – 同一个 BUF_A,同一时刻,不可能同时是 0.5ns 和 0.3ns
CRPR 找到 launch 和 capture clock 的最后公共分叉点(上例中的 BUF_A 输出),计算公共路径上的 max - min 差值,然后把这个差值加回到 slack 上,消除悲观度:
adjusted slack = original slack + 0.2ns
STA分析
看一个实际Time borrowing中时序报告的详细例子,两个寄存器(UFF0和UFF1)之间存在一个锁存器(ULAT1):

首先是UFF0-ULAT1的PATH
1 | Startpoint: UFF0 (rising edge-triggered flip-flop clocked by CLK) |
attention
library setup time是从 cell library(.lib 文件)中查到的,表示数据信号 D 必须在 gate 信号 G 关闭(CLK' 下降沿)之前 0.01ns 就稳定。这是保证 latch 能正确采样数据的最小时间裕量
ULAT1-UFFT1的PATH
1 | Startpoint: ULAT1 (positive level-sensitive latch clocked by CLK') |
attention
在考虑这条路径:UFF0-ULAT1-UFF1的时候,传统的PT分析将它拆成了两段独立分析
- UFF0 - ULAT1(setup check):ULAT1 是 capture 端,clock path 按 early/min 计算(OCV 分析希望 capture clock 尽早到达,收紧窗口)
- ULAT1 - UFF1(setup check):ULAT1 变成 launch 端,clock path 按 late/max 计算(OCV 分析希望 launch clock 尽晚到达)
问题在于:ULAT1 的同一段 clock path,在第一段分析中取 min delay,在第二段分析中取 max delay。正常情况下 CRPR 可以消除 launch/capture clock 公共路径上的悲观度,但这里两段分析是独立的,ULAT1 clock path 上的公共部分无法被 CRPR 修正。同一根时钟线被同时假设为又快又慢,产生了不真实的额外悲观度
1 | set_app_var timing_enable_through_paths true |
打开后,PT 把 latch 当作组合逻辑,将 UFF0 → ULAT1 → UFF1 作为一条完整路径分析。此时 launch clock 在 UFF0,capture clock 在 UFF1,CRPR 可以正常消除它们公共路径上的悲观度。Latch 的 time borrowing 仍然会考虑,但拆分分析带来的额外悲观度被消除了。
对 report_timing 的影响,在 through-path 模式下,latch 的 D pin 不再是 startpoint,只是一个穿越点:
report_timing -to $latch_d_pin:报告以 latch D pin 为终点的路径(传统视角)。report_timing -through $latch_d_pin:报告穿过 latch 的完整 FF → latch → FF 路径。report_timing -from $latch_d_pin:在 through-path 模式下不会有结果,因为 latch D pin 不再是合法的 startpoint
| 传统模式 | Through-Path 模式 | |
|---|---|---|
| 分析方式 | 拆成两段独立分析 | 合成一条 FF-to-FF 路径 |
| CRPR | 在 latch 边界处不完整 | 完整应用 |
| 悲观度 | 较高(偏保守) | 较低(更真实) |
| Latch D pin 角色 | 既是 endpoint 也是 startpoint | 只能是 endpoint 或穿越点 |
Lockup Latch
用latch来解决跨时钟域hold timing问题的应用
为了芯片测试的需要,我们会用Scan Chain的方式将绝大部分的寄存器串链起来,在不影响功能的情况下,以简单的方式测试电路中寄存器的良率。但是存在一种情况,前后相邻的两级寄存器如果时钟不一样(跨时钟域),如下图所示:

由于CLK1和CLK2为不同的时钟域,很难保证他们同步,假如CLK2相比CLK1有一段不确定的延迟Tskew,可大可小,那么很有可能FF1/CLK1->FF1/Q->FF2/SI这段延时Tdata会比Tskew小,造成hold timing违例

上一节提到Latch有time borrowing的功效,假如在两级寄存器之间加入一个latch,结构如下图所示:

CLK1低电平的时候,Lockup Latch是transparent,CLK1高电平的时候Lockup Latch一直保持上一拍的数据,这样即使CLK2有延迟,只要不超过CLK1高电平持续时间,就能保证hold timing没有问题

其他使用
Memory/Register File 接口:某些 SRAM 接口协议要求 latch 来保持地址/数据稳定
info
SRAM 是异步读取的——你给它地址,它就开始解码并输出数据,没有时钟沿的概念。这意味着地址线上的任何抖动都会被 SRAM 响应 在数据透明期SRAM地址可以跳转变化,等到数据所存的时候SRAM才进行读写操作
attention
如果没有锁存器,会有什么后果? 比如SRAM地址从100 -> 111 , 可能因为线延迟的关系,真是的跳变会是100 -> 110 -> 111,这样SRAM就会读取一个我们所不需要的一个地址
