3. Agilex时钟约束与SDC基础

在Agilex器件上做时序收敛,第一步不是打开Timing Analyzer看红色路径,而是把时钟约束写对。SDC(Synopsys Design Constraints)是Quartus Prime与Agilex时序引擎之间的“合同”:你告诉工具时钟从哪里来、频率多少、哪些时钟互不相关、哪些路径允许放宽,工具才能给出可信的建立/保持余量。本节围绕五类最常用的约束对象展开:create_clock、create_generated_clock、时钟组、时钟不确定性、时钟延迟,并说明它们在Agilex上的落地写法与常见误区。

一、create_clock:把物理时钟源翻译成时序起点

create_clock定义的是时序分析的“时间原点”。它并不改变硬件,只是告诉STA引擎:某个端口或某个内部节点上存在一个具有指定周期和波形的时钟。Agilex的参考时钟通常来自专用时钟输入引脚、收发器恢复时钟或片内PLL输出,约束时应优先绑定到真实存在的对象上。

# 主参考时钟:100 MHz,占空比50%,上升沿在0ns
create_clock -name clk_ref -period 10.000 -waveform {0.000 5.000} \
    [get_ports {ref_clk}]

# 若时钟从器件内部某节点进入,可绑定到引脚或寄存器时钟端
create_clock -name clk_core -period 5.000 -waveform {0.000 2.500} \
    [get_pins {pll_inst|clk_out[0]}]

关键点有三:其一,-name是后续所有约束引用的句柄,命名应体现频率与用途,如clk_ref_100m;其二,-period单位是ns,10.000即100 MHz,不要写成100;其三,-waveform必须落在[0, period)内且上升沿早于下降沿,否则Quartus会报错。若同一端口被重复约束,后写的会覆盖先写的,因此建议把主时钟集中放在一个*.sdc文件顶部。

二、create_generated_clock:描述PLL、分频与时钟使能派生

Agilex内部大量时钟由PLL、IOPLL、分频器或时钟使能产生。这些派生时钟不应再用create_clock重复定义,而应用create_generated_clock描述其与源时钟的相位/倍频关系。这样工具才能正确计算跨时钟域路径的公共周期与相位差。

# 源时钟
create_clock -name clk_in -period 10.000 [get_ports {ref_clk}]

# PLL输出:200 MHz,与源同相
create_generated_clock -name clk_200m \
    -source [get_pins {pll_inst|inclk[0]}] \
    -divide_by 1 -multiply_by 2 \
    [get_pins {pll_inst|clk_out[0]}]

# 分频时钟:50 MHz,反相
create_generated_clock -name clk_50m_inv \
    -source [get_ports {ref_clk}] \
    -divide_by 2 -invert \
    [get_pins {div_inst|q}]

这里-source必须指向源时钟所在的物理节点,而不是源时钟的名字;-divide_by与-multiply_by描述频率关系;-invert表示相对源时钟反相。若PLL配置了多个输出,应逐个输出写生成时钟,不要只写一个然后靠derive_pll_clocks自动推断——在Agilex上自动推断对级联PLL和动态重配置场景并不可靠,显式约束更稳。

三、时钟组:切断不相关时钟之间的分析

默认情况下,STA会分析任意两个时钟之间的路径。若两个时钟在功能上永不同时有效,或跨域路径已由同步器处理,就应把它们设为异步组,避免工具在无意义路径上浪费分析并产生虚假违例。

# 将三个时钟设为互不相关
set_clock_groups -asynchronous \
    -group {clk_ref_100m} \
    -group {clk_200m} \
    -group {clk_50m_inv}

# 仅切断两组之间的分析,组内仍分析
set_clock_groups -exclusive -group {clk_a clk_b} -group {clk_c}

-asynchronous表示组间完全异步,不做跨组时序分析;-exclusive表示组间互斥但组内仍分析。需要强调的是:时钟组只影响STA,不会自动插入同步器。若跨域路径没有两级触发器或握手逻辑,切断分析只是“看不见问题”,并不等于问题不存在。正确顺序是先在RTL中完成CDC处理,再用时钟组声明其异步属性。

四、时钟不确定性:为抖动、偏斜与PVT留余量

时钟不确定性(clock uncertainty)用于在时序方程中扣除抖动、时钟树偏斜和建模误差。Agilex的时钟网络经过全局时钟树,偏斜较小,但PLL抖动和外部参考抖动仍需显式建模。

# 对源时钟设置建立/保持不确定性
set_clock_uncertainty -setup 0.150 [get_clocks {clk_ref_100m}]
set_clock_uncertainty -hold  0.080 [get_clocks {clk_ref_100m}]

# 跨时钟域路径额外加余量
set_clock_uncertainty -from [get_clocks {clk_ref_100m}] \
                      -to   [get_clocks {clk_200m}] 0.200

数值来源应可追溯:例如参考晶振周期抖动±50 ps、PLL周期抖动±80 ps、时钟树偏斜±30 ps,则建立不确定性可取约0.15 ns。不要凭感觉写0.5 ns,过大的余量会掩盖真实问题,过小则流片后余量不足。建议在约束文件中以注释标明每个数值的来源。

五、时钟延迟:区分源延迟与网络延迟

时钟延迟分为源延迟(source latency,从时钟源到器件引脚)和网络延迟(network latency,从引脚到寄存器时钟端)。Agilex的全局时钟网络延迟由工具自动计算,通常不需要手动设置网络延迟;但源延迟在板级时钟经过缓冲器或长走线时必须补充。

# 源延迟:外部时钟到达FPGA引脚前的延迟
set_clock_latency -source 1.200 [get_clocks {clk_ref_100m}]

# 网络延迟:一般由工具自动处理,仅在特殊场景手动覆盖
set_clock_latency 0.300 [get_clocks {clk_ref_100m}]

若板级时钟经过时钟缓冲器,源延迟应包含缓冲器传播延迟与PCB走线延迟;若使用Agilex的专用时钟输入引脚,网络延迟交给工具即可。手动覆盖网络延迟会破坏工具对时钟树的建模,除非有明确依据,否则不建议。

六、多时钟约束在Agilex上的落地顺序

把上述约束组织成可维护的SDC文件,建议按以下顺序落地:先定义所有主时钟,再定义生成时钟,然后设置时钟组,接着补充不确定性与延迟,最后用derive_clock_uncertainty或手动检查覆盖情况。Quartus Prime在编译时会读取.sdc,可通过Report SDC和Check Timing确认约束是否被正确解析。

Agilex SDC 时钟约束落地关系图 外部参考时钟 ref_clk 100 MHz Agilex 专用时钟引脚 CLK_IN / 差分输入 收发器恢复时钟 RX_CLKOUT create_clock:定义主时钟周期、波形、命名 -period 10.000 -waveform {0 5} -name clk_ref_100m create_generated_clock:PLL / 分频 / 反相派生 -source -divide_by -multiply_by -invert 时钟组 set_clock_groups -asynchronous / -exclusive 时钟不确定性 set_clock_uncertainty -setup / -hold 时钟延迟 set_clock_latency -source / 网络延迟 Quartus Prime STA 时序分析引擎

最后给出一个可直接参考的约束检查清单,用于在Agilex工程中快速核对:

检查项正确做法常见错误
主时钟覆盖每个输入时钟端口都有create_clock遗漏收发器恢复时钟
生成时钟PLL每个输出单独约束只写一个输出,其余靠推断
时钟组异步域显式声明用时钟组掩盖未处理的CDC
不确定性数值有抖动/偏斜来源统一写0.5 ns
延迟仅补源延迟手动覆盖网络延迟
在Quartus Prime中执行Report SDC可查看所有已生效约束;执行Check Timing可确认是否存在未约束时钟或未约束路径。若报告出现“no clock”路径,优先回到create_clock与create_generated_clock检查覆盖范围。

把约束写对之后,Agilex的时序报告才具备参考价值。下一阶段再结合具体的CDC结构,判断哪些跨域路径需要同步器、哪些可以用时钟组声明异步,从而形成从约束到验证的完整闭环。