一、时序约束
时序引擎能够正确分析4种时序路径的前提是,用户已经进行了正确的时序约束。时序约束本质上就是告知时序引擎一些进行时序分析所必要的信息,这些信息只能由用户主动告知,时序引擎对有些信息可以自动推断,但是推断得到的信息不一定正确。关于时序路径的详细内容,请阅读:
FPGA时序分析与约束(5)——时序路径https://blog.csdn.net/apple_53311083/article/details/132641522
- 第一种路径需要约束Input_delay;
- 第二种路径需要约束时钟;
- 第三种路径需要约束output_delay;
- 第四种路径需要约束Max_delay/Min_delay;
二、时钟约束
首先用户必须要正确的约束时钟,时序引擎才能根据时钟信息进行各种时序检查。用户约束时钟时,一般有两种类型的时钟需要约束。
2.1 主时钟(Primary Clock)
主时钟(Primary Clock)有两种类型:第一种是从FPGA的全局时钟输入引脚输入的时钟;第二种是从高速收发器输出给用户的恢复时钟。
2.2 生成时钟(Generated Clock)
生成时钟(Generated Clock)有两种类型:第一种是由FPGA的专用时钟管理模块(PLL/MMCM)产生的时钟(这种时钟可以由时序引擎自动推断出来);第二种是由用户通过LUT或寄存器产生的时钟(这种时钟必须由用户手动约束)。
三、主时钟约束
3.1 create_clock
在设计中,我们用来说明主时钟的SDC指令是 create_clock 。该指令的BNF(Backus-Naur Form,巴斯科范式)为:
create_clock -period period_value[source_objects][-name clock_name][-waveform edge_list][-add][-comment comment_string]
3.1.1 定义时钟周期
-period 选项用于定义时钟周期。 时钟周期的单位由库时间单位推到得出,一般采用ns,时钟周期的值必须大于0。
设计者也可以使用 set_units 命令自行设定单位。
3.1.2 标识时钟源
create_clock 通常在时钟源的设计对象中进行声明。这些对象可以是端口、引脚或网络。如果在网络中定义时钟,则要确保网络中由驱动信号(引脚或者端口),否则时钟信号将没有信号源。一个时钟信号可能有多个时钟源。这种情况通常用在设计必须支持时钟切换冗余或者不同操作模式中。时钟切换通常的特点是锁相环可用,在主时钟停止运行时,可以打开冗余时钟。
以下图为例:
#代表作为时钟源的端口
create_clock -period 10 [get_ports A]ORcreate_clock -period 10 [get_nets N]OR#代表作为时钟源的引脚
#假设触发器实例名称FF
create_clock -period 10 [get_pins FF/P]
3.1.3 命名时钟
每个时钟定义都会给出时钟信号命名。用 -name 选项可以指定一个字符串作为时钟名称。当 -name 选项没有明确指定字符串并且时钟已经被声明,工具将指定自己的名字给时钟信号命名。对于前边给出的第一个例子,时钟信号的名称设定为A。在SDC中,时钟信号的名称是至关重要的。时钟信号一旦被定义并且命名,所有其他依赖于此时钟的SDC指令只需要提到时钟信号的名称,而不需要提供其他任何特征。当提到时钟信号名字的时候,时钟信号的所有特征就都知道了。时钟名称提供了更加简单的方法来统称时钟信号的所有特征。
3.1.4 指定占空比
时钟信号的占空比用 -waveform 选项来指定。
-waveform {<rise_time><fall_time>}
<rise_time>表示上升沿时刻,默认值为0;<fall_time>表示下降沿时刻,默认值是时钟周期的一半。单位也是ns。举个简单的例子:
create_clock -period 10 -name CLK -waveform{5 10} [get_ports A]
表示的就是在t = 5时刻出现上升沿,在t = 10时刻出现下降沿。如下图所示:
接下来我们考虑下面的这种情况:在一个时钟周期内,时钟沿在 t = 4时下降,接着在t = 5时上升。由于该-waveform 选项只能按照先上升沿再下降沿的顺序来表示,并且数值都是单调递增的,因此我们必须考虑两个时钟周期内时钟信号的变化。在两个时钟周期内,该时钟信号在 t = 5时出现第一个上升沿,接着在 t = 14时出现一个下降沿。因此该时钟信号表示为:
create_clock -period 10 -name CLK -waveform {5 14} [get_ports C2]
3.1.5 同源多时钟
许多设计需要在时钟源指定多个时钟,从而满足多I/O速度协议的需求。可以采用-add的方式实现,这里暂时不做展开。
3.1.6 注释时钟
可以采用-comment的方式实现对于时钟的注释。增加SDC的可读性和可以移植性。
3.2 主时钟约束
主时钟约束时,准确地指定时钟源的物理节点至关重要。下面通过几个简单的例子看下如何使用create_clock进行主时钟约束。
3.2.1 引脚输入的主时钟约束
如下图所示,名为sysclk的引脚是FPGA内部寄存器的时钟源。
对于该输入时钟的约束如下:
create_clock -name SysClk -period 10 -waveform {0 5} {get_ports sysclk}
在这个主时钟约束中,定义了名为sysclk的物理节点产生的时钟,它的周期是10ns,占空比为50%,命名为SysClk。
3.2.2 高速传输器输出的主时钟约束
高速传输器的输出时钟网络,经过时钟管理单元(CMT)之后,产生多个不同的生成时钟。在这种应用中,通常需要将高速传输器的输出时钟网络作为主时钟约束。
对该高速传输器输出的时钟网络的约束如下:
create_clock -name rxclk -period 6.667 [get_nets gt0/RXOUTCLK]
这个主时钟约束中,定义了名为 gt0/RXOUTCLK 的物理节点产生的时钟,它的周期为6.667ns,占空比为50%(没有定义时的默认占空比),该主时钟名称定义为rxclk。
3.3.3 硬件原语输出的主时钟约束
对于一些硬件原语的输出时钟引脚,若与其输入时钟之间没有很强的因果相关性,也可以将这个硬件原语的输出引脚作为时钟源进行主时钟约束,如下图所示,推荐使用instA/OUT作为主时钟节点。
而下图中的另一个例子,从输入引脚 sysclk 经过不同的 BUFG 所产生的时钟clk0(BFUG0)和clk1(BUFG1)分别作为时序路径中的一对源寄存器(reg1)和目的寄存器(reg2)的输入时钟。若此时还是指定BUFG原语的输出端作为主时钟约束的根节点,就可能由于clk0和clk1之间时钟偏斜差异而导致时序分析结果的误差。在这种情况下,clk0、clk1和输入时钟 sysclk 存在很强的因果相关性,只需要直接对源时钟 sysclk 进行主时钟约束,就能覆盖时钟 clk0 和 clk1 所驱动的所有时序路径。
3.3.4 差分信号的主时钟约束
一个差分缓冲器(IBUFDS)产生的单端时钟信号作为 PLL 的输入时钟。在这种情况下,只需要对差分缓冲器的输入正端(sys_clk,p)进行主时钟约束即可。因为在指定了差分时钟的正端引脚之后,其负端引脚就是固定的,时序分析工具能够自动识别。若同时对差分缓冲器的输入正端和负端进行主时钟约束,反而会导致产生不真实的 CDC(Clock Domin Crossing)路径。
这个差分时钟的约束脚本如下:
create_clock -name sysclk -period 3.33 [get_ports sys_clk_p]