这章节描述了对于多样的输入、输出路径的时序分析流程,以及几个常用的接口。特殊端口的时序分析,如SRAM;以及对于源同步接口的时序分析,也有讲到,如DDR SDRAM。
目录
输入路径的延迟指定 (Path Delay Specification to Inputs)
输出路径的延迟指定(External Path Delays for Output)
9.1 IO接口
本小节展示了如何对DUA的输入输出接口进行约束。晚些将会讲到对于SRAM DDR SDRAM的时序约束。
9.1.1 输入接口
有两种方法指定输入接口的时序
- 以AC特性的形式指定DUA输入端口的波形
- 指定了连接输入端口的外部逻辑的路径延时
指定输入端口的波形
指定的波形中,在CLKP的上升沿到来之前,CIN保持4.3ns的稳定,并且持续到上升沿之后的2ns。考虑8ns的周期,从虚拟触发器到CIN的组合逻辑所用时间最多为3.7ns(最大延时)。这可以保证数据在上升沿到来前4.3ns就保持了稳定。因此,这部分延时的指定,也可以指定为外部输入延时最大为3.7ns。在上升沿之后,数据需要保持2ns的稳定。这也意味着从外部虚拟触发器到CIN端口的延时至少为2.0ns。因此,这部分延时的指定,也可以指定为外部输入延时最小为2ns。
这部分可以这样理解:外部输入延时最大为3.7ns,如果大于了3.7ns,那么对于下一个捕获有效沿,就无法使得CIN端口提前4.3ns稳定。外部输入延时最小为2ns,如果小于了2ns,那么对于同一时刻的捕获有效沿,有可能造成重写的问题。所以最大外部延时为3.7ns,最小外部延时为2ns。
create_clock -name CLKP -period 8 [get_ports CLKP]
set_input_delay -min 2.0 -clock CLKP [get_ports CIN]
set_input_delay -max 3.7 -clock CLKP [get_ports CIN]
建立时间检查DUA内部的延时小于4.3ns,触发器可以捕获正确的数据。下面是保持时间报告:
这个保持时间检查保证最早的数据在有效边沿过去后的2ns发生变化,不会重写前面的数据。
输入路径的延迟指定 (Path Delay Specification to Inputs)
当连接了输入端口的外部组合逻辑的延时知道后,这项任务就变的简单了。任何沿着外部组合逻辑路径的延时都会被加起来,延时是使用set_input_delay指令进行指定的。
上图中,Tck2q Tc1的延时被加起来用来计算外部延时,两者加起来即可。下面指定的延时是INIT端口相对于RCLK端口的延时。
create_clock -name RCLK -period 10 [get_ports RCLK]
set_input_delay -max 6.2 -clock RCLK [get_ports INIT]
set_input_delay -min 3.0 -clock RCLK [get_ports INIT]
时序报告与先前的类似。注意,当计算设计内部触发器的数据引脚的数据到达时间的时候,计算得到最大延时还是最小延时,取决于进行的是最大延时路径检查(setup),还是最小延时路径检查(hold)。如上图中,max为6.2,那么就要考虑能否满足紧接着的下个时钟沿的建立时间要求;min为3,那么就要考虑是否数据传输的过快,会对相同时钟边沿捕获的数据造成重写的问题。
9.1.2 输出接口
同样也有两种方法用来指定输出端口的时序要求
- 以AC特性的形式指定DUA输出端口的波形
- 指定了连接输出端口的外部逻辑的路径延时
指定输出端口的波形
下图中,输出端口QOUT的数据应在CLKP的时钟沿到来前保持2ns稳定,在时钟沿到来后再保持1.5ns稳定。通常可以要求连接QOUT的外部逻辑的建立、保持时间来满足以上的约束值。
下面是对于端口的约束条件,输出路径的最大延时指定为2ns,这将会保证QOUT在2ns的窗口期之前变化。输出路径的最小延时指定为-1.5ns,用来确保输出QOUT上1.5ns的保持时间需求。解释一下,就是QOUT在CLKP下一个上升沿到来之前2ns已经稳定,所以外部延时QOUT相对于CLKP为2.0。QOUT在上升沿到来之后1.5ns仍然能稳定,所以为了满足保持时间的要求(也就是不被重写),QOUT相对于CLKP为-1.5ns。
create_clock -name CLKP -period 6 \
-waveform {0 3} [get_ports CLKP}
# Setup delay of virtual flip-flop:
set_output_delay -clock CLKP -max 2.0 [get_ports QOUT]
# Hold time for virtual flip-flop:
set_output_delay -clock CLKP -min -1.5 [get_ports QOUT]
建立时间检查, 将会从下个时钟沿减去外部延时,来确定数据的到达时间是否满足要求。
最小的输出路径延时将会从捕获时钟边沿减去,用来检查DUA输出端口的最早的到达时间能否满足保持时间的要求。上面的保持时间报告中,数据1.02ns就到了,但是要求数据最早1.55ns到,所以违例了。因为无法保证QOUT在1.55ns内保持稳定。
输出路径的延迟指定(External Path Delays for Output)
在这例子中,外部逻辑的路径延时被显式的指定了出来。
最大的输出延时设定,从Tc2_max和Tsetup获得。为了完成DUA内部触发器和虚拟触发器之前的建立时间检查,最大的输出延时将会指定为Tc2_max + Tsetup。最小的路径延时由Tc2_min和Thold获得。由于捕获触发器的保持时间被添加到了捕获时钟的路径中,因此最小输出路径延时被指定为Tc2_min-Thold.
解释一下:对于外部的虚拟触发器,需要有0.6ns的建立时间,0.15ns的保持时间。意味着从RDY到捕获时钟的下个有效沿,最大延时为3.1ns,最小延时为1.45ns,可以把保持时间理解为负的建立时间。可以用下面的图来解释。所以其实3.1也好,1.45也好,都是从指定端口到下一个触发器的时钟的延迟值。
create_clock -name SCLK -period 5 [get_ports SCLK]
# Setup of the external logic (Tc2_max = 2.5,
# Tsetup = 0.6):
set_output_delay -max 3.1 -clock SCLK [get_ports RDY]
# Hold of the external logic (Tc2_min=1.6, Thold=0.15):
set_output_delay -min 1.45 -clock SCLK [get_ports RDY]
时序报告相类似。
9.1.3 时序窗口内部的输出变化
本节考虑特殊情况,当输出只能在相对于时钟沿的时序窗口内发生改变时,可以指定输出延迟约束来验证时序,在验证源同步(source synchronous)接口的时序时尤其常用。在源同步接口会与数据一起输出,这种情况下,通常对于数据以及时钟之间有特殊的时序要求,比如说要求数据在时钟上升沿周围的一小段时序窗口内变化。
这里数据只能在时钟上升沿前的2ns内或者上升沿后的1ns内进行变化,这与要求数据引脚在时钟上升沿附近的指定时序窗口中保持稳定,还是有很大不同的。我们创建了衍生时钟CLK_STROBE,其主时钟为CLKM。这是为了方便指定接口的有关时序。
create_clock -name CLKM -period 6 [get_ports CLKM}
create_generated_clock -name CLK_STROBE -source CLKM \
-divide_by 1 [get_ports CLK_STROBE]
通过结合建立时间和保持时间检查以及多周期路径约束来指定时序窗口要求。该时序要求对应在单个上升沿(相同的发起沿和捕获沿)处进行建立时间检查。我们将多周期建立时间指定为0(默认为1)。此外保持时间检查需要在相同边沿进行,所以我们将多周期保持时间设置为-1.
set_multicycle_path 0 -setup -to [get_ports DATAQ]
set_multicycle_path -1 -hold -to [get_ports DATAQ]
然后指定输出有关于CLK_STROBE时钟的约束。可以注意到min选项的时间大于max选项的时间,这个异常情况的出现是因为输出延迟并没有对应于实际的逻辑块。源同步接口的set_output_delay的约束只是一种机制,目的是为了把输出约束在时钟边沿的窗口内。因此,才会出现上面的反常情况。
set_output_delay -max -1.0 -clock CLK_STROBE \
[get_ports DATAQ]
set_output_delay -min +2.0 -clock CLK_STROBE \
[get_ports DATAQ]
思考:-1.0代表比时钟晚1ns到,+2.0代表比时钟早2ns到。为什么上面用max下面用min,因为互换就violated。
下面的是建立时间报告:
对建立时间检查而言,通常会在下个周期进行捕获,但是这里是在同一个时钟沿进行的捕获。报告中显示出,数据DATAQ在0.61ns发生了变化,CLK_STROBE在0.09ns发生了变化。由于DATAQ可以在CLK_STROBE的1ns内发生变化,在计算上0.3ns的时钟不确定度之后,仍有0.18ns的裕度。
下面是保持时间报告:
这个报告中DATAQ在0.48ns到达,CLK_STROBE在0.09ns发生变化。因为数据可以在时钟的前2ns之内发生变化,再算上50ps的始终不确定度,我们最终可以得到2.35ns的裕度。
9.2 SRAM接口
所有在SRAM接口中数据传输,只会在时钟的有效边沿上进行。所有数据仅在有效边沿处被SRAM锁存或者被SRAM发射。包含SRAM接口的信号有命令(command),地址,控制输出总线(control output bus),双向数据总线(bidirectional data bus),时钟。
- 写周期:DUA向SRAM写数据,数据、地址由DUA去往SRAM,并且在时钟的有效边沿进行锁存。
- 读周期:地址仍由DUA去往SRAM,但是数据由SRAM去往DUA。
因此,地址和控制信号(下图中的单向箭头)是单向的,由DUA去往SRAM。通常会在时钟的路径上放置延迟锁定环DLL(delay locked loop),DLL允许在必要时延迟时钟信号,以解决由于PVT和其它外部变化而导致接口上各种信号的延迟变化。考虑到这种变化,数据的传输(无论是读还是写)将会有良好的时序裕度。
上图展示了SRAM典型接口的AC特性,请注意data in 、data out是从SRAM的方向来看的。从SRAM的 data out,是DUA的输入;SRAM的 data in 也是DUA的输出。可以使用以下的约束。
# First define primary clock at the output of UPLL0:
create_clock -name PLL_CLK -period 5 [get_pins UPLL0/CLKOUT]
# Next define a generated clock at clock output pin of DUA:
create_generated_clock -name SRAM_CLK \
-source [get_pins UPLL0/CLKOUT] -divide_by 1 \
[get_ports SRAM_CLK]
# Constrain the address and control:
set_output_delay -max 1.5 -clock SRAM_CLK \
[get_ports ADDR[0]]
set_output_delay -min -0.5 -clock SRAM_CLK \
[get_ports ADDR[0]]
. . .
# Constrain the data going out of DUA:
set_output_delay -max 1.7 -clock SRAM_CLK [get_ports DQ[0]]
set_output_delay -min -0.8 -clock SRAM_CLK [get_ports DQ[0]]
# Constrain the data coming into the DUA:
set_input_delay -max 3.2 -clock SRAM_CLK [get_ports DQ[0]]
set_input_delay -min 1.7 -clock SRAM_CLK [get_ports DQ[0]]
. . .
下面的是地址引脚的建立时间检查报告:
这个建立时间检查验证了,地址信号是否比SRAM_CLK信号早1.5ns到达内存(Memory)。
保持时间检查验证了时钟边沿过后0.5ns,地址信号是否没发生改变。
9.3 DDR SDRAM接口
DDR SDRAM接口可以被视为前一节描述的SRAM接口的扩展。与SRAM接口一样,DDR SDRAM接口也有两条主要的总线。下图展示了DUA与SDRAM之间的总线连接和总线方向。第一条总线包括命令(command)、地址和控制引脚(通常称为CAC,Command Address Control),采用标准方案,即在内存时钟的一个时钟边沿上(或每个时钟周期一次)发送信息。两条双向总线包括DQ,数据总线;和DQS,数据选通信号。DDR接口的主要区别是双向数据选通信号DQS。DQS选通信号是为一组数据信号提供的,这使得数据信号(每字节一个或每半字节一个)与选通信号的时序紧密匹配;如果整个数据总线使用共同的时钟信号,这样的紧密匹配可能是不可行的。双向时钟选通信号DQS用于读取和写入操作。时钟用于在其上升沿、下降沿捕获数据(即双倍数据速率)。在SDRAM的读模式下,DQ总线与数据选通时钟DQS是源同步的(而不是内存时钟),即在从SDRAM发送数据时,DQ和DQS是对齐的。在另一方向,即当DUA发送数据时,DQS会发生90度相位偏移。请注意,数据DQ和选通信号DQS的边缘都是由DUA内部的内存时钟派生的。
如上所说,一个数据选通SRTOBE信号,管着一组DQ信号,包含4-8bit。这样做是为了DQS和DQ所有位之间的偏移平衡更加容易达到。举例来说,一个DQS搭配一个字节的DQ,一共是9个信号(9=8+1)需要被平衡。这种情况肯定比平衡72位的数据总线更加容易。
下图中,展示了DDR SDRAM的CAC总线在DUA处的AC特性
# DDRCLK is typically a generated clock of the PLL
# clock internal to DUA:
create_generated_clock -name DDRCLK \
-source [get_pins UPLL0/CLKOUT]\
-divide_by 1 [get_ports DDRCLK]
# Set output constraints for each bit of CAC:
set_output_delay -max 0.75 -clock DDRCLK [get_ports CAC]
set_output_delay -min -0.75 -clock DDRCLK [get_ports CAC]
地址总线可能会驱动比时钟更大的负载,尤其是与无缓冲的内存模块形成接口的时候。在这种情况下,地址信号对存储器的延迟要比时钟信号大。这种延迟的差异,可能会导致AC特性不同于上图所示。
DQ DQS信号的对齐方式对于读周期和写周期可能会有不同。下面讲。
9.3.1 读周期
在读周期中,内存输出的数据会与DQS边沿对齐。下图为波形,DQ、DQS代表内存引脚上的信号。数据信号DQ,在DQS的每个边沿被内存送出,DQ的转换是与DQS的上升沿、下降沿对齐的。由于DQS数据选通信号、DQ数据信号名义上是与彼此对齐的,通常DUA内部的内存控制器会用到DLL(或任何能延迟1/4周期的方法)来延迟DQS信号从而使得延迟的DQS信号的边沿边沿对齐于数据有效窗口的中心。如下图中,经过DLL延时之后的DQS信号的边沿与DQ数据窗口的中心是重合的。即使DQ数据信号和DQS数据选通信号在内存中名义上是对齐的,但他们在DUA的内存控制器内部可能不再对齐。这可能是由于IO缓冲器的延时不同,也有可能是因为PCB互连走线的问题。
下图中展示了基础的 读 原理,上升沿触发的触发器UFF0在DQS_DLL的上升沿捕获数据DQ,下降沿触发的触发器同理。即使DQ路径上没有描绘DLL,在某些设计中,数据路径中同样包含DLL。这可以使得延时可控(考虑到某些不可控因素)。这样的话,数据就可以在数据有效窗口的中间被采样。
为了约束控制器的读接口,我们根据DQS定义了一个时钟,相对于该时钟指定了输入的延迟。
create_clock -period 5 -name DQS [get_ports DQS]
在这里假设内存读取接口以200MHz的频率工作,这对应于每2.5ns采样一次DQ信号。因为上图中UFF0,UFF5分别在正负边沿捕获数据,所以数据在所有边沿都会被捕获,输入约束需要对正负边沿都要指定。
# For rising clock edge:
set_input_delay 0.4 -max -clock DQS [get_ports DQ]
set_input_delay -0.4 -min -clock DQS [get_ports DQ]
# This is with respect to clock rising edge (default).
# Similarly for falling edge:
set_input_delay 0.35 -max -clock DQS -clock_fall \
[get_ports DQ]
set_input_delay -0.35 -min -clock DQS -clock_fall \
[get_ports DQ]
# The launch and capture are on the same edge:
set_multicycle_path 0 -setup -to UFF0/D
set_multicycle_path 0 -setup -to UFF5/D
输入延时代表了DQ和DQS的边沿在DUA引脚上的时间差。即使这两个信号是从内存中通常是同时输出的,他们在时序方面仍会有所偏差。因此,DUA内部的控制器设计应考虑两个信号之间可能存在偏差。我们假设建立时间的要求为0.05ns,保持时间的要求为0.03ns,DLL的延时为1.25ns也就是周期的1/4。下面是建立时间的报告,首先是上升沿的:
然后是下降沿触发器作为终点的的建立时间报告,为什么是2.50,因为这是个半周期约束,上升沿下降沿都会捕获。
接下来是保持时间的时序报告:
保持时间,下降沿触发的触发器作为终点的报告:
9.3.2 写周期
在写周期中,DQS信号与DUA内存控制器输出的DQ信号相差1/4的周期,所以DQS选通信号可以用来捕获数据。
下图中是内存引脚上需要的波形,DQS信号的边沿必须与内存引脚上DQ信号的时序窗口的中心对齐。请注意,仍然是由于IO缓冲器延迟不匹配或者PCB互连走线的变化,仅在存储控制器(DUA内部)中对齐DQ和DQS还不足以使这些信号在SDRAM存储器引脚处真正的对齐。因此,DUA通常在写周期中使用额外的DLL去进行控制,以实现DQS和DQ信号之间所需的四分之一周期偏移(offset)。
对于这个模式的输出约束,取决于控制器内部的时钟是如何产生的,考虑下面两种情况。
从上面的这个图可以看出,建立时间检查的起点为发射DQ数据的时钟边沿,终点为下一个DQS的边沿;保持时间的起点为发射DQ数据的时钟边沿,终点为前一个DQS的边沿。下面两种情况都适用。
情况1:内部2倍时钟
如果有一个内部时钟的频率是DDR时钟频率的2倍,输出逻辑与下图类似。DLL可以用来使DQS产生偏移,这样的话必要时就可以满足建立时间以及保持时间的要求。有些情况下,我们不用DLL,而是用一个负边沿触发的触发器去满足90度的偏移。
输出可以采用如下的约束。DQ输出引脚同样需要相对于衍生时钟DQS设置约束。
# 166MHz (333Mbps) DDR; 2x clock is at 333MHz:
create_clock -period 3 [get_ports CLK2X]
# Define a 1x generated clock at the output of flip-flop:
create_generated_clock -name pre_DQS -source CLK2X \
-divide_by 2 [get_pins UFF1/Q]
# Create the delayed version as DQS assuming 1.5ns DLL delay:
create_generated_clock -name DQS -source UFF1/Q \
-edges {1 2 3} -edge_shift {1.5 1.5 1.5} [get_ports DQS]
我们假设在DQ和DQS之间进行的建立时间检查,对于上升沿捕获,建立时间为0.25ns,对于下降沿捕获,建立时间为0.4ns。进行的保持时间检查,对于上升沿捕获,保持时间为0.15ns,下降沿捕获为0.2ns。DLL的延时为1.5ns,波形如下图所示。DQ与DQ@Memory有走线延迟,DQS也是同理的。
set_output_delay -clock DQS -max 0.25 -rise [get_ports DQ]
# Default above is rising clock.
set_output_delay -clock DQS -max 0.4 -fall [get_ports DQ]
# If setup requirements are different for falling edge of DQS,
# that can be specified by using the -clock_fall option.
set_output_delay -clock DQS -min -0.15 -rise DQ
set_output_delay -clock DQS -min -0.2 -fall DQ
建立时间检查的时序报告如下。这个检查起点是两倍速时钟在0ns的上升沿,他将数据DQ发送,检查的终点是1.5nsDQS的上升沿。由于内存处的DQS位于DQ的引脚的中间,所以进行建立时间检查或者保持时间检查应该轻松?所以检查前面这条触发器--输出路径的时序?
注意,四分之一周期的延时出现在DQS上升沿的第一行中,而不是DLL的实例UDLL的那行中,这是因为DLL的延时已经建模成为了DQS衍生时钟的一部分,而不是DLL时序弧中的一部分。
接下来的是保持时间报告,起点是二倍速时钟的上升沿(在3ns),终点是DQS的前一个上升沿(在1.5ns)。
情况2:内部的一倍速时钟
此时输出电路类似于下图:
有两个触发器用来产生DQ数据,第一个触发器NEGEDGE_REG,由时钟CLK1X的下降沿触发,第二个触发器POSEDGE_REG,由时钟CLK1X的上升沿触发。每个触发器都在恰当的边缘锁存数据,然后时钟作为复用器的选择信号对两个触发器锁存的数据进行复用。CLK1X为高时候,NEGEDGE_REG的输出数据送到了DQ;CLK1X为低时候,POSEDGE_REG的输出数据送到了DQ。因此,CLK1X的每个边缘都有数据到达DQ。值得注意的是,每个触发器都是有半个周期的时间将数据传播到MUX的输入端,所以数据早在选择信号有效之前就准备好了。有关的波形如下图所示。
输出延时进行如下约束:
# Create the 1x clock:
create_clock -name CLK1X -period 6 [get_ports CLK1X]
# Define a generated clock at DQS. It is a divide-by-1 of
# CLK1X. Assume a quarter-cycle delay of 1.5ns on UDLL0:
create_generated_clock -name DQS -source CLK1X \
-edges {1 2 3} -edge_shift {1.5 1.5 1.5} [get_ports DQS]
# Define a setup check of 0.25 and 0.3 between DQ and DQS
# pins on rising and falling edge of clock:
set_output_delay -max 0.25 -clock DQS [get_ports DQ]
set_output_delay -max 0.3 -clock DQS -clock_fall \
[get_ports DQ]
set_output_delay -min -0.2 -clock DQS [get_ports DQ]
set_output_delay -min -0.27 -clock DQS -clock_fall \
[get_ports DQ]
建立时间、保持时间检查验证了从复用器到输出端口的时序。其中一个建立时间检查从CLK1X在MUX输入端的正边沿开始,结束于DQS的上升沿;另一个建立时间检查从CLK1X在MUX输入端的负边沿开始,结束于DQS的下降沿。
下面是另一份建立时间的报告,执行从CLK1X的负边沿(选择了POSEDGE_REG的数据)到DQS的负边沿。
下面是保持时间报告,从CLK1X的正边沿开始 ,到DQS的前一个负边沿结束。
下面是另一份保持时间报告,从CLK1X的负边沿开始,到DQS的前一个正边沿结束。
上述的接口时序分析忽略了输出端口负载影响,可以使用set_load设置输出负载,获得更高的精确度。STA同样可以使用电路仿真来补充,实现可靠的DRAM时序。
对于DDR接口,DQ和DQS信号通常在读写模式下使用ODT(On-Die Termination,第一级终端)来减少由于DRAM和DUA之间阻抗不匹配引起的反射。由于ODT终端的存在,静态时序分析所使用的时序模型无法提供足够的精度。设计师可能需要使用替代机制,如详细的电路级仿真,来验证DRAM接口的信号完整性和时序。
9.4 DAC接口
下图中的DAC接口,高速时钟可以将数据传输到DAC的低速时钟接口。XPLL_CLK为高速时钟,DAC_CLK为低速时钟。后者是前者的二分频,DAC接口的建立时间检查和保持时间检查都与DAC_CLK的下降沿有关。这个例子中,建立时间认为是一个单周期路径,即使从快时钟域到慢时钟域有可能出现多周期的情况(有可能出现多周期,每隔几个周期捕获一次数据,但是在这里不考虑,仅考虑最严格的建立时间检查)。下图中XPLL_CLK的正边沿发送数据,DAC_CLK的负边沿捕获数据。
建立时间报告:
保持时间报告:
保持时间检查的捕获边沿是建立时间的捕获边沿的前一个边沿。最严苛的情况是,是发射数据边沿和捕获边沿处于相同的时间,就如报告中那样。
部分内容翻译自“Static Timing Analysis for Nanometer Designs A Practical Approach” 欢迎指正!