第三章 时钟约束入门:create_clock 命令详解

时钟,是数字芯片的“心跳”。

没有时钟约束,STA 就无从谈起。我见过不少新手,上来就写 create_clock,但波形长什么样、占空比设多少、多时钟之间怎么处理,全凭感觉。结果呢?后仿一堆时序违例,查半天才发现是时钟定义错了。

这一章,咱们就把时钟约束的底子打牢。

3.1 create_clock 命令的基本用法

create_clock 是 SDC 里最基础的命令。它的作用很简单——告诉工具:这里有一个时钟,周期多少,波形长什么样。

基本语法长这样:

create_clock -name <时钟名> -period <周期> -waveform {<上升沿时间> <下降沿时间>} [<端口/引脚列表>]

举个例子:

create_clock -name clk_sys -period 10.0 -waveform {0 5} [get_ports clk_in]

这条命令的意思是:在端口 clk_in 上定义一个名为 clk_sys 的时钟,周期 10ns,上升沿在 0ns,下降沿在 5ns——也就是 50% 占空比。

我的习惯: 给时钟命名时,尽量用有意义的名称,比如 clk_core、clk_mem、clk_io。别用 clk1、clk2 这种,等报告里出现几十个时钟时,你会后悔的。

3.2 时钟周期与占空比设置

周期和占空比,是时钟的两个核心参数。

周期(Period):单位是 ns,对应频率的倒数。比如 10ns 周期就是 100MHz。

占空比(Duty Cycle):高电平时间占整个周期的比例。默认是 50%,但实际芯片里不一定。

来看几个常见场景:

场景 周期 占空比 waveform 参数
标准 50% 时钟 10.0 ns 50% {0 5}
60% 高电平时钟 8.0 ns 60% {0 4.8}
非 0 起始沿 10.0 ns 50% {2 7}
DDR 双沿时钟 5.0 ns 50% {0 2.5}

注意第三行——上升沿从 2ns 开始。为什么会有这种需求?

我在一个项目中遇到过,PLL 输出的时钟相位偏移了 2ns,但周期还是 10ns。这时候直接写 {0 5} 就错了,必须按实际波形来。

避坑指南: 我曾经因为 waveform 写错,导致 setup 和 hold 检查的参考沿全乱了。记住:-waveform 里的第一个值是上升沿时间,第二个是下降沿时间。顺序搞反,时序分析全错。

3.3 多时钟与时钟组(clock groups)

一个芯片里通常不止一个时钟。CPU 核一个时钟,总线一个时钟,外设又一个时钟。这些时钟之间怎么处理?

默认情况下,工具会分析所有时钟之间的路径。但很多跨时钟域的路径是异步的,不需要做时序分析。如果放任不管,工具会报一堆假违例,浪费你大量时间。

这时候就需要 set_clock_groups 了。

3.3.1 什么是时钟组

时钟组,就是把互不同步的时钟归到不同组里。工具只分析同一组内的时钟路径,跨组的路径直接忽略。

语法:

set_clock_groups -asynchronous -group {clk_a clk_b} -group {clk_c}

这条命令告诉工具:clk_a 和 clk_b 是同步的,它们之间要分析;clk_c 跟前面两个是异步的,跨组路径不用管。

3.3.2 三种关系

关系 命令选项 含义
同步 (默认) 时钟之间有确定的相位关系,需要 STA
异步 -asynchronous 时钟之间无相位关系,跨时钟路径不做 STA
互斥 -logically_exclusive 物理上不会同时存在的时钟,比如 MUX 选择
核心原则: 异步时钟必须用 set_clock_groups -asynchronous 隔开。否则工具会分析不存在的路径,产生大量假违例。你想想看,一个 100MHz 的时钟和一个 1kHz 的时钟,它们之间的路径怎么可能满足 setup?

3.4 本章知识体系

下面这张图,帮你把这一章的核心逻辑串起来:

时钟约束知识体系 时钟约束核心知识体系 时钟约束 create_clock 命令 周期 & 占空比 时钟组 (clock groups) -name 命名 -period 周期 -waveform 波形 50% 默认占空比 非 50% 占空比 非 0 起始沿 -asynchronous -logically_exclusive -physically_exclusive 核心原则 1. 每个时钟必须有唯一的 -name 和正确的 -period 2. 异步时钟必须用 set_clock_groups 隔开,避免假违例 3. waveform 参数必须与实际硬件波形一致

3.5 实战建议

说了这么多,最后给几个实在的建议:

  • 先画时钟树草图:动手写 SDC 之前,把芯片里所有时钟的来源、频率、相位关系画出来。我每次做新项目都这么干,能避免 80% 的时钟定义错误。
  • 用 report_clock 验证:写完 create_clock 后,立刻跑 report_clock 看看波形对不对。别等到综合完了才发现。
  • 异步时钟尽早分组:在 SDC 的开头就把 set_clock_groups 写好。拖到后面,你很容易漏掉某个跨时钟域路径。
  • 别滥用 -logically_exclusive:这个选项只用于物理上不会同时存在的时钟。如果你不确定,就用 -asynchronous,更安全。
再强调一次: 我曾经接手过一个项目,前任工程师把所有时钟都放在一个组里,没做任何隔离。结果 STA 报告里有两千多条违例,其中一千八百条是假的。光清理这些假违例就花了一周。别走这条路。

时钟约束是 STA 的基石。这一章的内容,说白了就是三件事:定义时钟、设对波形、分好组。把这三件事做扎实了,后面的路就好走了。