以下是对“Timing Constraints Skill”的中文翻译:
专家技能,用于开发和验证时序约束。编写SDC(Synopsys设计约束)和XDC文件,用于FPGA时序关闭。
概述
时序约束技能使得FPGA设计能够全面开发时序约束,支持:
- 时钟定义(create_clock, create_generated_clock)
- 输入/输出延迟约束
- 假路径识别和规范
- 多周期路径约束与建立/保持
- 时钟组和关系
- 约束覆盖验证
- 供应商特定的XDC扩展
能力
1. 主时钟定义
定义进入FPGA的主时钟:
# 输入引脚上的主时钟
create_clock -name sys_clk -period 10.000 [get_ports clk_100mhz]
# 具有占空比规格的时钟
create_clock -name sys_clk -period 10.000 -waveform {0 5} [get_ports clk_100mhz]
# 多个主时钟
create_clock -name clk_a -period 8.000 [get_ports clk_125mhz]
create_clock -name clk_b -period 6.667 [get_ports clk_150mhz]
# GT/收发器参考上的时钟
create_clock -name gt_refclk -period 6.400 [get_ports gt_refclk_p]
# 虚拟时钟(用于没有物理引脚的I/O时序)
create_clock -name virt_clk -period 10.000
2. 产生时钟定义
定义从主时钟派生的时钟:
# MMCM/PLL输出时钟(在Vivado中自动派生)
create_generated_clock -name clk_200mhz \
-source [get_pins mmcm_inst/CLKIN1] \
-master_clock sys_clk \
-divide_by 1 -multiply_by 2 \
[get_pins mmcm_inst/CLKOUT0]
# 逻辑中的时钟分频器
create_generated_clock -name clk_div2 \
-source [get_pins clk_div_reg/C] \
-divide_by 2 \
[get_pins clk_div_reg/Q]
# 时钟多路复用器输出
create_generated_clock -name clk_mux_a \
-source [get_pins clk_mux/I0] \
-master_clock clk_a \
-add \
[get_pins clk_mux/O]
create_generated_clock -name clk_mux_b \
-source [get_pins clk_mux/I1] \
-master_clock clk_b \
-add \
[get_pins clk_mux/O]
3. 输入延迟约束
约束输入信号的时序:
# 系统同步输入(源同步)
# 数据在时钟边缘后到达
set_input_delay -clock sys_clk -max 3.0 [get_ports data_in[*]]
set_input_delay -clock sys_clk -min 1.0 [get_ports data_in[*]]
# DDR输入(双数据速率)
set_input_delay -clock ddr_clk -max 2.5 [get_ports ddr_data[*]]
set_input_delay -clock ddr_clk -min 0.5 [get_ports ddr_data[*]]
set_input_delay -clock ddr_clk -max 2.5 [get_ports ddr_data[*]] -clock_fall -add_delay
set_input_delay -clock ddr_clk -min 0.5 [get_ports ddr_data[*]] -clock_fall -add_delay
# 相对于虚拟时钟的输入
set_input_delay -clock virt_clk -max 4.0 [get_ports async_data[*]]
set_input_delay -clock virt_clk -min 0.0 [get_ports async_data[*]]
# 源同步接口与转发时钟
set_input_delay -clock rx_clk -max 2.0 [get_ports rx_data[*]]
set_input_delay -clock rx_clk -min 0.5 [get_ports rx_data[*]]
4. 输出延迟约束
约束输出信号的时序:
# 系统同步输出
# 下游设备设置时间:2ns,保持时间:0.5ns
# 板级延迟:0.5ns
set_output_delay -clock sys_clk -max 2.5 [get_ports data_out[*]]
set_output_delay -clock sys_clk -min -0.5 [get_ports data_out[*]]
# DDR输出
set_output_delay -clock ddr_clk -max 1.5 [get_ports ddr_out[*]]
set_output_delay -clock ddr_clk -min 0.0 [get_ports ddr_out[*]]
set_output_delay -clock ddr_clk -max 1.5 [get_ports ddr_out[*]] -clock_fall -add_delay
set_output_delay -clock ddr_clk -min 0.0 [get_ports ddr_out[*]] -clock_fall -add_delay
# 源同步输出与产生时钟
set_output_delay -clock tx_clk -max 1.0 [get_ports tx_data[*]]
set_output_delay -clock tx_clk -min -0.5 [get_ports tx_data[*]]
5. 假路径约束
识别并约束不需要时序分析的路径:
# 异步复位 - 无时序要求
set_false_path -from [get_ports rst_n]
# 静态配置寄存器
set_false_path -from [get_cells config_reg[*]]
# 时钟域交叉(由同步器处理)
set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]
set_false_path -from [get_clocks clk_b] -to [get_clocks clk_a]
# 特定CDC路径(更精确)
set_false_path -from [get_cells -hier -filter {NAME =~ *cdc_src_reg*}] \
-to [get_cells -hier -filter {NAME =~ *cdc_dst_sync_reg[0]*}]
# 互斥时钟多路复用路径
set_false_path -from [get_clocks clk_mux_a] -to [get_clocks clk_mux_b]
set_false_path -from [get_clocks clk_mux_b] -to [get_clocks clk_mux_a]
# 调试信号
set_false_path -to [get_ports debug_*]
6. 多周期路径约束
定义需要多个时钟周期的路径:
# 2周期路径用于慢操作
# 数据在2个时钟周期内有效
set_multicycle_path 2 -setup -from [get_cells slow_src_reg] -to [get_cells slow_dst_reg]
set_multicycle_path 1 -hold -from [get_cells slow_src_reg] -to [get_cells slow_dst_reg]
# 基于使能信号的多周期
# 数据在使能断言时每4个周期变化一次
set_multicycle_path 4 -setup -from [get_cells data_reg[*]] -to [get_cells proc_reg[*]]
set_multicycle_path 3 -hold -from [get_cells data_reg[*]] -to [get_cells proc_reg[*]]
# 相位移时钟多周期
# 源时钟领先目标90度
set_multicycle_path 1 -setup -start -from [get_clocks clk_0] -to [get_clocks clk_90]
# 宽总线操作的多周期
set_multicycle_path 2 -setup -from [get_pins wide_reg[*]/C] -to [get_pins result_reg[*]/D]
set_multicycle_path 1 -hold -from [get_pins wide_reg[*]/C] -to [get_pins result_reg[*]/D]
7. 时钟组
定义时钟之间的关系:
# 异步时钟组 - 它们之间没有时序
set_clock_groups -asynchronous \
-group [get_clocks clk_100mhz] \
-group [get_clocks clk_125mhz] \
-group [get_clocks gt_refclk]
# 物理上互斥的时钟(多路复用选择)
set_clock_groups -physically_exclusive \
-group [get_clocks clk_mux_a] \
-group [get_clocks clk_mux_b]
# 逻辑上互斥的时钟(运行时选择)
set_clock_groups -logically_exclusive \
-group [get_clocks pll_config_a] \
-group [get_clocks pll_config_b]
8. CDC的最大延迟
为CDC路径约束最大延迟(假路径的替代方案):
# CDC同步器的最大延迟约束
# 确保数据在下一个时钟边缘之前稳定
set_max_delay -datapath_only -from [get_cells cdc_src_reg] \
-to [get_cells cdc_sync_reg[0]] 5.0
# CDC FIFO灰码指针
set_max_delay -datapath_only \
-from [get_cells wr_ptr_gray_reg[*]] \
-to [get_cells rd_ptr_sync_reg[0][*]] \
[expr {$period_clk_wr * 0.8}]
9. 物理约束(XDC扩展)
Xilinx特定的物理约束:
# I/O标准
set_property IOSTANDARD LVCMOS33 [get_ports gpio[*]]
set_property IOSTANDARD LVDS_25 [get_ports {lvds_p lvds_n}]
# 引脚位置
set_property PACKAGE_PIN H16 [get_ports clk_100mhz]
set_property PACKAGE_PIN R14 [get_ports rst_n]
# I/O驱动强度
set_property DRIVE 8 [get_ports data_out[*]]
set_property SLEW FAST [get_ports high_speed_out]
# 输入终止
set_property PULLUP TRUE [get_ports config_pin]
set_property IBUF_LOW_PWR FALSE [get_ports high_speed_in]
# 时钟输入缓冲器类型
set_property CLOCK_DEDICATED_ROUTE BACKBONE [get_nets clk_100mhz_IBUF]
流程集成
这项技能与以下流程集成:
| 流程 | 集成点 |
|---|---|
timing-constraints.js |
主要约束开发 |
timing-closure.js |
约束细化以实现闭合 |
synthesis-optimization.js |
约束感知综合 |
cdc-design.js |
CDC约束生成 |
工作流程
1. 时钟分析
## 时钟域分析
| 时钟 | 频率 | 源 | 域 |
|-------|-----------|--------|--------|
| sys_clk | 100 MHz | 外部 | 主要 |
| clk_200 | 200 MHz | MMCM | 处理 |
| rx_clk | 125 MHz | PHY | RX路径 |
| tx_clk | 125 MHz | MMCM | TX路径 |
## 时钟关系
- sys_clk -> clk_200: 同步(MMCM)
- sys_clk <-> rx_clk: 异步
- tx_clk -> rx_clk: 异步
2. 生成约束
# 生成的输出文件:
# - constraints/clocks.xdc - 时钟定义
# - constraints/io_timing.xdc - I/O延迟约束
# - constraints/cdc.xdc - CDC约束
# - constraints/exceptions.xdc - 假/多周期路径
# - constraints/physical.xdc - 引脚分配
3. 验证约束
# 在Vivado中
report_clocks
report_clock_interaction
report_timing_summary -delay_type min_max
check_timing
report_methodology
输出架构
{
"constraints": {
"clocks": {
"primary": [
{ "name": "sys_clk", "period": 10.0, "port": "clk_100mhz" }
],
"generated": [
{ "name": "clk_200", "source": "sys_clk", "multiply": 2, "divide": 1 }
]
},
"ioTiming": {
"inputs": [
{ "port": "data_in[*]", "clock": "sys_clk", "maxDelay": 3.0, "minDelay": 1.0 }
],
"outputs": [
{ "port": "data_out[*]", "clock": "sys_clk", "maxDelay": 2.5, "minDelay": -0.5 }
]
},
"exceptions": {
"falsePaths": [
{ "from": "rst_n", "reason": "异步复位" }
],
"multicyclePaths": [
{ "from": "slow_reg", "to": "proc_reg", "setup": 2, "hold": 1 }
]
},
"clockGroups": [
{ "type": "asynchronous", "clocks": ["sys_clk", "rx_clk"] }
]
},
"validation": {
"allClocksConstrained": true,
"allIOConstrained": true,
"noUnconstrainedPaths": true,
"cdcCovered": true
},
"artifacts": [
"constraints/clocks.xdc",
"constraints/io_timing.xdc",
"constraints/cdc.xdc",
"constraints/exceptions.xdc"
]
}
常见模式
源同步接口
# 源同步输入(时钟与数据一起转发)
create_clock -name rx_clk -period 8.000 [get_ports rx_clk]
set_input_delay -clock rx_clk -max 2.5 [get_ports rx_data[*]]
set_input_delay -clock rx_clk -min 0.5 [get_ports rx_data[*]]
# 源同步输出(FPGA生成时钟)
create_generated_clock -name tx_clk \
-source [get_pins mmcm/CLKOUT1] \
[get_ports tx_clk]
set_output_delay -clock tx_clk -max 1.0 [get_ports tx_data[*]]
set_output_delay -clock tx_clk -min -0.5 [get_ports tx_data[*]]
异步FIFO CDC
# FIFO灰码指针交叉
set_max_delay -datapath_only \
-from [get_cells fifo_inst/wr_ptr_gray_reg[*]] \
-to [get_cells fifo_inst/wr_ptr_sync_reg[0][*]] 8.0
set_max_delay -datapath_only \
-from [get_cells fifo_inst/rd_ptr_gray_reg[*]] \
-to [get_cells fifo_inst/rd_ptr_sync_reg[0][*]] 10.0
复位同步器
# 异步复位输入
set_false_path -from [get_ports rst_n]
# 复位同步器 - 允许2个时钟周期
set_max_delay -from [get_cells rst_sync_reg[0]] \
-to [get_cells rst_sync_reg[1]] \
[get_property PERIOD [get_clocks sys_clk]]
最佳实践
时钟约束
- 总是明确定义所有时钟源
- 使用有意义的时钟名称
- 文档化时钟关系
- 使用
report_clocks验证
I/O约束
- 根据数据表计算延迟
- 包括板级延迟
- 使用虚拟时钟进行异步接口
- 文档化延迟预算
CDC处理
- 优先使用
set_max_delay -datapath_only而不是set_false_path - 确保同步器ASYNC_REG属性已设置
- 使用
report_cdc验证覆盖范围 - 文档化所有CDC路径
验证
- 实施前运行
check_timing - 查看
report_timing_summary以查找未约束的路径 - 使用
report_methodology进行DRC检查 - 文档化所有时序豁免
参考资料
- Synopsys设计约束(SDC)参考
- Xilinx UG903: Vivado使用约束
- Xilinx UG949: UltraFast设计方法
- Intel Quartus Prime时序分析仪
另见
timing-constraints.js- 时序约束开发过程timing-closure.js- 时序闭合方法- SK-005: CDC分析技能
- AG-002: FPGA时序专家代理