3. 时序约束入门:主时钟约束、生成时钟约束、输入延迟约束、输出延迟约束
各位同学,咱们今天聊聊时序约束。说实话,我刚入行那会儿,觉得约束就是随便写几行代码,让工具别报错就行。结果呢?第一次做高速接口项目,板子调了三天三夜,信号就是不稳定。后来才发现,是约束没写对。
时序约束这东西,说白了就是告诉工具:你的设计要在什么样的时钟环境下工作,数据什么时候来,什么时候走。工具知道了这些,才能帮你把路径优化好。今天咱们就把最基础的四种约束讲透。
3.1 主时钟约束(create_clock)
主时钟约束是所有约束的起点。你想想看,没有时钟,时序分析就无从谈起。我习惯把主时钟想象成一个心跳,它决定了整个系统的节奏。
语法很简单,但参数要搞明白:
create_clock -name sys_clk -period 10.000 [get_ports clk_in]
这里 -period 10.000 表示周期是10ns,也就是100MHz。注意单位是纳秒,别写成毫秒,我见过有人犯这种低级错误。
有时候时钟不是50%占空比,比如DDR接口需要25%占空比的时钟。这时候用 -waveform 参数:
create_clock -name ddr_clk -period 5.000 -waveform {0.000 1.250} [get_ports ddr_clk_p]
这个波形参数的意思是:上升沿在0ns,下降沿在1.25ns。说白了就是高电平只占1/4周期。
3.2 生成时钟约束(create_generated_clock)
生成时钟,就是由主时钟通过PLL或分频电路产生的时钟。工具不会自动识别这些时钟的关系,你得手动告诉它。
最常见的场景是PLL输出:
create_generated_clock -name pll_out -source [get_ports clk_in] \
-divide_by 2 [get_pins pll/clk_out]
这里 -source 指定源时钟,-divide_by 2 表示二分频。如果是倍频,用 -multiply_by。
还有一种情况是分频时钟,比如用寄存器做二分频:
create_generated_clock -name div2_clk -source [get_ports clk_in] \
-edges {1 3 5} [get_pins div_reg/Q]
-edges 参数指定了生成时钟的边沿对应源时钟的哪些边沿。1、3、5表示源时钟的第1、3、5个边沿。这个写法比较绕,我建议你直接用 -divide_by 和 -multiply_by,更直观。
3.3 输入延迟约束(set_input_delay)
输入延迟约束,是告诉工具数据从外部芯片到达FPGA引脚需要多长时间。这个时间包括PCB走线延迟、外部芯片的时钟到输出延迟(Tco)等。
语法是这样的:
set_input_delay -clock sys_clk -max 2.500 [get_ports data_in]
-max 表示最大延迟,-min 表示最小延迟。为什么要有最大最小?因为芯片的延迟有工艺偏差,你得考虑最坏情况。
实际项目中,输入延迟的计算公式是:
输入延迟 = 外部芯片Tco + PCB走线延迟
举个例子,外部芯片的Tco是1.5ns,PCB走线延迟0.8ns,那输入延迟就是2.3ns。我一般会留0.2ns的余量,写成2.5ns。
关键点:输入延迟是相对于时钟边沿的。如果数据在时钟上升沿之后到达,延迟是正值;如果数据在时钟上升沿之前到达,延迟是负值。嗯,负延迟的情况很少见,但DDR接口中确实存在。
3.4 输出延迟约束(set_output_delay)
输出延迟约束和输入延迟是对称的。它告诉工具:数据从FPGA输出后,外部芯片需要多长时间才能正确采样。
语法:
set_output_delay -clock sys_clk -max 3.000 [get_ports data_out]
输出延迟的计算公式:
输出延迟 = 外部芯片建立时间 + PCB走线延迟
比如外部芯片的建立时间是2ns,PCB走线延迟0.8ns,那输出延迟就是2.8ns。我习惯写成3ns,留点余量。
这里有个容易混淆的地方:输出延迟是相对于FPGA内部的时钟边沿,而不是外部时钟。你想想看,FPGA在时钟上升沿输出数据,数据经过PCB到达外部芯片,外部芯片要在下一个时钟上升沿采样。这个时间差就是输出延迟要约束的。
3.5 四种约束的配合使用
这四种约束不是孤立的,它们共同构成了完整的时序约束体系。我画个简单的流程:
- 先定义所有主时钟(create_clock)
- 再定义所有生成时钟(create_generated_clock)
- 然后定义输入延迟(set_input_delay)
- 最后定义输出延迟(set_output_delay)
顺序很重要。你想想看,没有时钟,输入输出延迟就无从谈起。所以时钟约束必须放在最前面。
实际项目中,我还会加一些辅助约束,比如set_clock_uncertainty(时钟不确定性)、set_false_path(伪路径)等。但今天咱们先把这四种基础约束吃透。
好了,今天的内容就到这里。下节课咱们聊聊如何分析时序报告,以及常见的违例怎么修。有什么问题,欢迎课后交流。