目录
一、时序约束的步骤
二、时序网表和路径
2.1 时序网表
2.2 时序路径
三、时序约束的方式
三、时钟约束
3.1 主时钟约束
3.2 虚拟时钟约束
3.3 衍生时钟约束
3.4 时钟组约束
3.5 时钟特性约束
3.6 时钟延时约束
一、时序约束的步骤
上一章了解了时序分析和约束的很多基本概念(FPGA时序分析与时序约束(一)),只需要去理解如何进行时序分析即可,而我们只需要对综合工具提出时序约束的要求,综合工具就会对这些路径进行计算。而时序约束可以分为四个主要步骤进行:
1.时钟约束(Create Clock):主时钟、虚拟时钟、衍生时钟;
2.输入/输出接口约束(Input/Output Delays,I/O约束):系统同步接口、源同步接口;
3.时钟分组和跨时钟约束(Clock Groups and CDC):异步;
4.时序例外约束(Timing Exceptions):多周期路径、虚假路径。
而一般时序分析会涉及三种情况:
最好的条件(Best Case):速度最快的情况;
最坏的条件(Worst Case):速度最慢的情况;
典型的条件(Typical Case):速度介于最快和最慢之间。
这三种情况分别对应如下细节:
BCF(Best Case):fast process, lowest temperature, high voltage;
WCS (Worst Case):slow process, high temperature, lowest voltage;
TYP(Typical Case):typical process, nominal temperature, nominal voltage.
其中芯片工艺(process)、电压(voltage)、温度(temperature) 共同组成了PVT组合,时序分析工具会根据仿真需求使用不同的PVT组合用于STA分析。
芯片的工艺角(Process corner)分为快速工艺角(fast corner)、慢速工艺角(slow corner)、典型工艺角(typical corner)。时序分析工具通过Worst corner 保证建立时间的时序,通过Best corner来保证保持时间的时序。由于一般情况下设计以建立时间违例为主,所以时序分析工具默认使用slow corner。
二、时序网表和路径
2.1 时序网表
时序网表包含设计的综合节点和连接,时序分析工具需要网表来执行时序分析。而时序网表将设计单元划分成单元、管脚、网络和端口来进行延迟的测量。
- Cell : FPGA中的基本结构单元,包含查找表、寄存器、DSP、I/O单元等;
- Pin : Cell的输入输出端口(这里的Pins不包括器件的输入输出引脚);
- Net : 两个或多个互连组件的集合;
- Port : 顶层逻辑的输入输出端口,对应已经分配的器件引脚。
2.2 时序路径
时序分析工具对设计中确定的所有时序路径的时序性能进行测量,时序路径分为四种:
边沿路径 (Edge paths) —从端口到管脚,从管脚到管脚以及从管脚到端口的连接; 时钟路径(Clock paths)—从器件端口或内部生成的时钟管脚到寄存器的时钟管脚的连接; 数据路径(Data paths)—从顺序单元的端口或数据输出管脚到另一个顺序单元的端口或数据输入管脚的连接; 异步路径(Asynchronous paths)—从另一个顺序单元(例如异步复位或异步清除)的异步管脚或端口的连接。
三、时序约束的方式
到现在位置,时序约束的概念、步骤、顺序等都概念都有所了解了,那么到底怎么样进行时序约束呢?时序约束的方式主要有两种:
1.通过FPGA开发工具进行约束,Intel的是Timing Analyzer,Xilinx的是Vavado
2.通过Tcl语言手动编写约束脚本
三、时钟约束
3.1 主时钟约束
主时钟通常是FPGA器件外部的板级时钟(如晶振、数据传输的同步时钟等)或FPGA的高速收发器输出数据的同步恢复时钟信号等。
通过create_clock命令可对主时钟进行约束定义:
create_clock -name<clock_name> -period<period> -waveform{<rise_time><fall_time>} [get_ports<port_name>]
- <clock_name>是设计者自定义的主时钟名称,后续的约束若引用已经定义的时钟,<clock_name>是唯一的引用标识,如果不指定,则会默认使用<port_name>所指定的时钟物理节点;
- <period>是主时钟周期,单位ns,取值必须大于0;
- waveform的<rise_time>是上升沿时间,默认0,<fall_time>是下降沿时间,默认时钟周期一半,单位都是ns;这里可以理解为设置时钟的占空比,如果没有定义wavaform则默认占空比50%;
- get_ports表示定义的时钟是FPGA的物理引脚,<port_name>是定义的主时钟的物理节点名称;FPGA内部网络也能作为主时钟的物理节点,使用get_nets定义;高速收发器的引脚则使用get_pins定义。
主时钟是帮助时序分析工具定义了时序路径分析的一个时间零点,时钟传输过程中的延时和不确定性都会基于这个时间零点进行计算和分析,而其他时序约束也会经常引用主时钟,因此在时序约束中必须先定义主时钟约束。
引脚输入的主时钟约束
如上图是一个周期10ns、占空比50%的时钟sysclk接在sysclk端口上,对该输入时钟引脚的约束为:
//周期10ns、占空比50%的时钟sysclk接在sysclk端口上
create_clock -period 10 [get_ports sysclk]
//周期10ns、占空比25%、相位偏移 90° 的时钟devclk接在ClkIn端口上
create_clock -name devclk -period 10 -waveform {2.5 5} [get_ports ClkIn]
高速收发器主时钟约束
高速传输器的输出时钟网络经过时钟管理单元mmcn0后会产生多个衍生时钟,此时通常要将GT传输器的输出时钟作为主时钟约束。
//周期3.33ns、占空比50%的时钟rxclk接在gt0/RXOUTCLK端口上
create_clock -name rxclk -period 3.33 [get_ports gt0/RXOUTCLK]
差分信号主时钟约束
当差分缓冲器产生的时钟信号作为PLL的输入时钟,只需要对差分缓冲器的正端(SYS_CLK_clk_p)进行约束,因为指定正端后时序分析工具就能自动识别负端。
create_clock -name sysclk -period 3.33 [get_ports SYS_CLK_clk_p]
3.2 虚拟时钟约束
在主时钟约束的基本语法中,get_ports是指主时钟的实际物理节点,意味着这个主时钟是实际存在于FPGA器件内的。但虚拟时钟并不是实际存在于FPGA器件中,因此在物理上没有连接任何网表,它是用于描述时序数据引脚的外部时钟信号。
虚拟时钟必须在输入和输出延迟约束使用之前定义,通常被用于以下情况的输入和输出延时约束:
- 时序分析(一般是I/O引脚相关的时序路径)的参考时钟不是FPGA内部的设计时钟(主时钟);
- 与FPGA器件的I/O路径相关的内部驱动时钟与其板级驱动时钟不同步;
- 对I/O的驱动时钟指定一些特殊的抖动和延时值,但不希望影响此时钟在FPGA内部的时钟传输特性。
虚拟时钟同样用create_clock定义,只是省去了端口项,:
create_clock -name<clock_name> -period<period> -waveform{<rise_time><fall_time>}
比如在一些引脚上的数据信号,其同步时钟只存在于外部芯片,并不存在于FPGA器件,此时为了时序分析也需要定义一个时钟用于外部时钟信号,即虚拟时钟。
系统同步接口的虚拟时钟约束
如上图reg2的驱动时钟是真实存在的,可以对其进行主时钟约束;外部芯片中reg1的主时钟并不会传输到fpga器件,可以对其进行虚拟时钟约束:
create_clock -period 10 -name VIR_SLK -waveform {0 5}
create_clock -period 10 -name SYS_SLK -waveform {0 5} [get_clock clk]
3.3 衍生时钟约束
衍生时钟是主时钟进行分频,倍频,相移而产生的时钟信号,如时钟管理单元MMCM或PLL所驱动产生的时钟信号。衍生时钟的定义取决于主时钟的特性,衍生时钟的约束必须指定时钟源,这个时钟源可以是一个已经约束好的主时钟或另一个衍生时钟。衍生时钟并不直接定义频率、占空比等参数,而是定义其与时钟源的相对关系,如分频系数、倍频系数、相移差值、占空比转换等。
衍生时钟分为自动衍生时钟(Auto-Generated Clocks)和手动衍生时钟。时序工具能够识别时钟调整模块(Clock Modifying Blocks,CMB)及其基于输入主时钟的变更特性,自动为CMB输出的时钟信号创建约束。若设计者认为自动衍生时钟有误,可使用create_generate_clock命令重新约束衍生时钟,此时自动衍生时钟的约束会被忽略。
可以通过check_timing命令查看为约束的主时钟和衍生始终,通过create_generate_clock命令对其进行约束:
create_generated_clock -name <generated_clock_name>
-source <master_clock_source_pin_or_port>
-multiply_by <mult_factor>\
-divide_by <div_factor>
<pin_or_port>
<generated_clock_name>是用于指定的衍生时钟名,若不指定则由pin_or_port指定物理节点作为名称;
<master_clock_source_pin_or_port>指定源时钟的物理节点(引脚或端口),源时钟可以是一个主时钟、虚拟时钟或者衍生时钟;
<mult_factor>指定衍生时钟相对于源时钟的倍频系数,值必须大于等于1.0;
<div_factor>指定衍生时钟相对于源时钟的分频系数,值必须大于等于1.0;
<pin_or_port>指定衍生时钟的物理节点、引脚或端口名称。
2分频的衍射时钟约束
// 主时钟约束
create_clock -name clkin -period 10 [get_ports clkin]
// 将clkin作为时钟源
create_generated_clock -name clkdiv2 -source [get_ports clkin] -divide_by 2 [get_pins REGA/Q]
// 将REGA作为时钟源
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -divide_by 2 [get_pins REGA/Q]
可以使用 -edges选项直接描述基于主时钟边沿的生成时钟的波形,而不是使用-divide_by选项。参数是主时钟边沿索引列表,用于定义生成的时钟边沿的时间位置,从时钟上升沿开始。
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -edges {1 3 5} [get_pins REGA/Q]
可以使用-divide_by、 -multiply_by实现分频和倍频
#4/3倍频的衍生时钟
create_generated_clock -name clkdiv4_3 -source [get_pins mmcm0/CLKIN] -multiply_by 4 -divide_by 3 [get_pins mmcm0/CLKOUT]
相位偏移的衍生时钟约束
可以使用-edges、-edge_shift实现占空比改变和相移,
# 生成占空比25%且相移90°的衍生时钟,主时钟的边沿分别为1、2、3,衍生时钟则需要将边沿移动2.5、0、2.5
# First rising edge: 0ns + 2.5ns = 2.5ns
# Falling edge: 5ns + 0ns = 5ns
# Second rising edge: 10ns + 2.5ns = 12.5ns
create_clock -name clkin -period 10 [get_ports clkin]
create_generated_clock -name clkshift -source [get_pins mmcm0/CLKIN] -edges {1 2 3} -edge_shift {2.5 0 2.5} [get_pins mmcm0/CLKOUT]
3.4 时钟组约束
时钟组能够指定设计中哪些时钟是不相关的。默认情况下,时序分析工具会对所有时钟之间的路径进行时序分析,除非通过使用时钟组(clock group)或虚假路径(false path)约束来指定。set_clock_groups命令禁用所识别的时钟组之间的时序分析,而不禁用同一组内的时钟之间的时序分析。
可以多次使用-group选项指定多个时钟组。如果在设计中没有时钟组中的时钟,则时钟组为空。set_clock_groups约束仅当至少有两个组有效且不为空时才有效。如果只有一个组仍然有效,而所有其他组都为空,则不应用set_clock_groups约束,会生成错误消息。
set_clock_groups [-asynchronous] [-exclusive] -group <names>
- -asynchronous : 指定互斥时钟(与 -exclusive 选项相同)。存在是为了兼容性;
- -exclusive : 指定互斥时钟;
- -group : 有效目的地(使用Tcl字符串匹配来匹配字符串模式)。
时钟组提供了一种快速便捷的方法来指定哪些时钟不相关。异步时钟是那些完全不相关的时钟(例如,具有不同的理想时钟源)。独占时钟是那些不同时激活的时钟(例如,多路复用时钟)。 TimeQuest 将“-exclusive”和“-asynchronous”这两个选项视为相同。 set_clock_groups 的结果是任何组中的所有时钟都与其他组中的所有时钟相分离。该命令相当于从每个组中的每个时钟到每个其他组中的每个时钟调用 set_false_path ,反之亦然,使得 set_clock_groups 更容易指定以切割时钟域。使用单个 -group 选项告诉 TimeQuest 将这组时钟从设计中的所有其他时钟中删除,包括将来创建的时钟。
create_clock -period 10.000 -name clkA [get_ports sysclk[0]]
create_clock -period 10.000 -name clkB [get_ports sysclk[1]]
# 设置clkA和clkB为互斥时钟
set_clock_groups -exclusive -group {clkA} -group {clkB}
# 上一行相当于以下两条命令
set_false_path -from [get_clocks clkA] -to [get_clocks clkB]
set_false_path -from [get_clocks clkB] -to [get_clocks clkA]
3.5 时钟特性约束
当时钟在FPGA内部传输时,会因为时钟走线路径和硬件噪声引起时钟沿的延时和波形变化,称其为时钟传输延时和不确定性。在FPGA的时序分析中主要通过时钟抖动(Clock Jitter)和时钟不确定性(Clock Uncertainty)进行约束定义。
3.5.1 时钟抖动
输入抖动
输入抖动是连续的时钟边缘与标准或理想的时钟到达时间的差值。输入抖动是一个绝对值,表示时钟边缘两侧的变化。set_input_jitter命令只能约束主时钟,不能用于约束衍生时钟的抖动值。但除了MMCM或PLL外,主时钟设定的抖动值会传递给它的衍生时钟。
set_input_jitter [get_clock<clock_name>] <jitter_in_ns>
- get_clocks用于指定需要约束抖动值的主时钟名<clock_name>;
- <jitter_in_ns>指定抖动值,取值必须大于等于0ns。
# 约束多个主时钟的抖动值需要多条set_input_jitter命令
set_input_jitter clk1 0.3
set_input_jitter clk2 0.3
# 主时钟抖动值会传递给衍生时钟
create_clock -period 10 -name sysclk [get_ports clk]
create_generated_clock -name sysclkdiv2 -source [get_ports sysclk] -divide_by 2 [get_pins clkgen/sysclkdiv/Q]
set_input_jitter sysclk 0.15
系统抖动
系统抖动是由于电源噪声、板噪声或任何额外的系统抖动造成的整体抖动,使用set_system_jitter命令约束系统抖动。
set_input_jitter <jitter_in_ns>
- <jitter_in_ns>指定所有时钟的系统抖动值,取值必须大于等于0ns。
3.5.2 时钟不确定性
除时钟抖动以外的所有可能影响时钟周期性偏差的因素,都可以使用set_clock_uncertainty命令进行约束。
set_clock_uncertainty -setup -form [get_clocks<clock0_name>] -to [get_clocks<clock1_name>]<uncertainy_value>
- -setup表示定义建立时间检查的时钟不确定性时间,也可以使用hold表示定义保持时间检查的时钟不确定性时间;如果不指定-setup和-hold,则表示同时定义建立时间坚持和保持时间检查的不确定时间;
- -from指定源时钟,-to指定目标时钟,对于非跨时钟域的路径一般不需要指定from和to;
- get_clocks用于指定实际的屋里节点名称;
- <uncertainty_value> 指定时钟不确定时间,单位ns。
为了区分set_clock_uncertainty命令约束的时钟不确定值和用于时序分析计算出的时钟不确定时间,称set_clock_uncertainty命令约束的时钟不确定值为用户不确定性(User Uncertainty,UU)时间,UU时用于时序分析的时钟不确定时间的一部分。
时序分析的Clock Uncertainty时间计算公式如下:
- Tsj是最坏情况的系统抖动时间,由set_system_jitter设定值换算而来;
- Tij是set_input_jitter设定的输入抖动时间;
- Dj是由一些硬件原语(MMCM或PLL等)产生的离散时钟抖动;
- PE(Phase Error)是由MMCM或PLL等产生的相位误差,一般都有固定值;
- UU(User Uncertainty)是set_clock_uncertainty设定的时钟不确定性值。
而在进行建立时间关系和保持时间关系的Data Required Time计算时,都会将 Clock Uncertainty时间考虑在内。计算建立时间关系的数据需求时间时,时钟不确定时间作为一个加项;计算保持时间关系的数据需求时间时,时钟不确定时间作为一个减项。因此可以通过使用set_clock_uncertainty命令为某个时钟或某两个时钟之间的时序路径添加时序裕量。
# 为主时钟clk添加0.5ns裕量以添加改时钟的建立时间和保持时间
set_clock_uncertainty -from clk -to clk0 0.500
# 当源时钟和目的时钟时两个不同的主时钟且数据传输时双向的,将0.5ns的时钟不确定性分半设置
set_clock_uncertainty -from clk0 -to clk1 0.250 -setup
set_clock_uncertainty -from clk1 -to clk0 0.250 -setup
3.6 时钟延时约束
时钟到达寄存器输入端口的总延时包括了时钟源延时和时钟网络延时。
set_clock_latency [-clock<args>] [-rise] [-fall] [-min] [-max] [-source] <latency> <objects>
- [-clock]可选项,时钟名称<args>对应指定约束时钟<objects>;若不定义时钟<args>,则时钟延时值<latency>将会应用于所有目标时钟<objects>所驱动的时序路径;
- [-rise][-fall]指定时钟延时的边沿;
- [-min][-max]指定时钟延时的最大值或最小值且只能指定其一;若不指定则延时值同时作为最大最小值进行定义;
- [-source]指定时钟延时的基本类型;若不指定则默认[-network]类型
- [-source]时钟源延时,约束用于定义时序分析时实际使用的时钟对于理想时钟波形的延时;
- [-network]时钟网络延时,约束用于定义时钟信号从设计中的某个指定节点传输到源寄存器的时钟输入端口的延时;
- <latency>指定时钟延时值,单位ns;
- <objects> 指定约束时钟的名称。
参考文献:
《FPGA时序约束与分析》
《正点原子FPGA静态时序分析与时序约束》
《Intel Quartus Prime Standard Edition用户指南: Timing Analyzer》
《Vivado Design Suite User Guide: Using Constraints(UG903)》
《Vivado Design Suite 用户指南: 设计分析与收敛技巧 (UG906)》