3、时序约束入门:SDC约束文件结构、时钟定义与生成时钟、输入输出延迟约束、时序例外
各位好,我是老李。在芯片后端干了十几年,我见过太多因为时序约束没写对,导致流片回来跑不起来的惨案。今天咱们就聊聊SDC约束文件——这东西说白了,就是你告诉工具:我的芯片到底该怎么跑。
3.1 SDC文件长什么样?
SDC的全称是Synopsys Design Constraints。嗯,名字挺唬人,其实就是一个文本文件。工具读它的时候,一行一行解析,告诉综合工具或STA工具:哪些路径要检查,哪些可以放水。
我个人习惯把SDC分成几个区块:
- 时钟定义:create_clock、create_generated_clock
- 输入输出延迟:set_input_delay、set_output_delay
- 时序例外:false_path、multicycle_path、max_delay等
- 其他约束:set_clock_uncertainty、set_clock_transition等
你想想看,一个芯片里成千上万条路径,工具不可能每条都按最严格的标准去检查。SDC就是告诉它:哪些是重点,哪些可以睁一只眼闭一只眼。
3.2 时钟定义——芯片的“心跳”
时钟是芯片里最关键的信号。没有时钟,所有寄存器都像没睡醒一样。定义时钟用create_clock命令。
create_clock -name clk_sys -period 10 [get_ports clk_in]
这条命令的意思是:在端口clk_in上创建一个名为clk_sys的时钟,周期10ns,也就是100MHz。
我在项目中遇到过一件事:有个同事把时钟周期写成了10ns,但实际PLL输出是5ns。结果综合出来的电路根本跑不到200MHz,流片回来直接废了。嗯,时钟周期写错,是新手最容易犯的错。
3.2.1 生成时钟(Generated Clock)
芯片里经常有分频、倍频的情况。比如PLL输出一个200MHz时钟,然后内部再分频成100MHz。这时候就要用create_generated_clock。
create_generated_clock -name clk_div2 -source [get_pins pll/clk_out] \
-divide_by 2 [get_pins divider/clk_out]
这里要注意:-source指定的是源时钟的引脚,不是端口。我见过有人写成get_ports,结果工具报错半天找不到原因。
get_pins或get_nets,不要用get_ports。因为源时钟可能经过了很多级缓冲,端口上的波形已经不准了。
3.3 输入输出延迟约束——芯片与外界的“握手”
芯片不是孤岛。它要和外部器件通信。输入延迟告诉工具:数据从外部到达芯片引脚,花了多少时间。输出延迟告诉工具:数据从芯片引脚到外部器件,需要多少时间。
3.3.1 输入延迟
set_input_delay -clock clk_sys -max 2.5 [get_ports data_in]
这条命令的意思是:数据data_in相对于时钟clk_sys,最大延迟是2.5ns。也就是说,时钟沿到来后,数据最晚2.5ns后才能稳定。
我曾经在一个项目中,输入延迟设得太小,结果工具以为数据到得很早,把路径优化得特别激进。流片回来发现,实际数据到得晚,setup违例了。嗯,这个坑我踩过。
3.3.2 输出延迟
set_output_delay -clock clk_sys -max 4.0 [get_ports data_out]
输出延迟的意思是:外部器件需要数据在时钟沿之后4.0ns内到达。所以芯片内部必须在时钟沿之后(周期-4.0ns)内把数据送出来。
3.4 时序例外——给工具“开绿灯”
不是所有路径都需要按一个时钟周期来检查。有些路径天生就慢,有些路径根本不需要检查。这时候就要用时序例外。
3.4.1 False Path(假路径)
假路径就是:这条路径永远不会被激活。比如跨时钟域的同步器路径,或者测试模式下的路径。
set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]
这条命令告诉工具:从clk_a到clk_b的所有路径,都不用检查时序。
我个人习惯:写false_path时,尽量用时钟域做范围,不要用具体的引脚。因为芯片迭代时,引脚名字可能会变,但时钟域名字一般不变。
3.4.2 Multicycle Path(多周期路径)
有些路径不需要在一个时钟周期内完成。比如从慢速模块到快速模块,或者某些计算需要多个周期才能稳定。
set_multicycle_path -setup 2 -from [get_pins reg_a/CK] -to [get_pins reg_b/D]
这条命令的意思是:从reg_a到reg_b的路径,允许2个时钟周期完成setup检查。hold检查默认会跟着调整,但有时需要单独设hold。
你想想看,如果一条路径需要2个周期才能稳定,你却按1个周期去约束,工具会拼命插缓冲器,面积和功耗都上去了。多周期路径就是告诉工具:别急,慢慢来。
3.5 知识体系总览
下面这张图,是我自己总结的SDC约束知识体系。你可以把它当成一个检查清单,写SDC时对照着看,不容易漏项。
3.6 写在最后
SDC约束这东西,看着简单,但坑特别多。我见过有人把时钟周期写反,有人把false_path写成了整个芯片,还有人忘了写生成时钟。嗯,这些我都经历过。
我的建议是:每写完一条约束,都问自己三个问题——这条约束对吗?覆盖了哪些路径?有没有遗漏?养成这个习惯,你的时序收敛会顺利很多。
好了,这一章就到这里。下一章咱们聊聊更深入的东西。
公众号:蓝海资料掘金营,微信deep3321