静态时序分析 第七章 配置STA环境

第7章 配置STA环境

   本章节描述了如何建立静态时序分析的环境。在分析STA结果时,正确的约束规范非常重要。正确的指定设计环境,STA才能找出设计中的所有时序问题。STA的准备工作包括,设置时钟、指定IO时序特性,设定伪路径和多周期路径。在进行下一章的时序验证之前,完全理解本章内容是非常重要的。

7.1 什么是STA环境?(What is the STA Environment?)

   大部分数字设计是同步的,从上一个时钟周期计算得到的数据在有效时钟沿被锁存在触发器中,请思考图7-1所示的典型同步设计。假设待分析设计(Design Under Analysis,DUA)和其他同步设计交互。这意味着DUA收到受时钟约束的触发器的数据,并把数据输出给DUA之外的另一个受时钟约束的触发器。
在这里插入图片描述
   为了对设计进行STA,需要给触发器指定时钟,需要给所有到该设计的路径和离开该设计的路径进行时序约束。
   图7-1中的例子假设只有1个时钟,且C1、C2、C3、C4以及C5代表组合逻辑块。组合逻辑块C1和C5在要分析的设计之外。
   在一个典型的设计中,会存在多个时钟以及从一个时钟域到另一个时钟域的很多路径。下面的小节描述了,在这种情况下是如何指定STA环境的。


7.2 指定时钟(Specifying Clocks)

   要定义一个时钟,我们需要提供以下信息:

  • 1)时钟源(Clock source):它可以是设计的一个端口,或者是设计内部单元的引脚(通常该单元是时钟生成逻辑的一部分)
  • 2)周期(Period):时钟的时序周期
  • 3)占空比(Duty Cyele):高电平持续时间(Positive Phase, 正相位),和低电平持续时间(Negative Phase, 负相位)
  • 4)沿时间(Edge Time):上升沿和下降沿的时间

   图7-2表示了基本定义。通过定义时钟,所有的内部时序路径(所有的触发器到触发器路径)都被约束了;这意味着只要有时钟约束,就可以分析所有的内部路径。时钟约束指定了触发器到触发器的路径只能占用1个时钟周期。我们之后会介绍这个要求(只占用1个时钟周期)是如何被放松的。
在这里插入图片描述


下面是一个基本的时钟约束规范
在这里插入图片描述

规范(Specification)和约束(Constraint)被当作同义词,都是SDC规范的一部分。
查看附录SDC关于场景中目标获取命令,比如会使用到get_ports和get_clocks。

   时钟的名字是SYSCLK,定义在端口SCLK。SYSCLK的周期指定为20单位,如果没有专门指定的话,默认的时间单位是ns(通常,时间单位会在技术库中指定)。在waveform中第1个参数指定了上升沿的发生时间,第2个参数指定了下降沿的发生时间。

   在waveform选项中,可以指定任意多个沿。但是所有的沿必须在同一个周期内。沿时间交替,从时间0之后第1个上升沿开始,然后是下降沿,然后是上升沿,以此类推。这意味着在沿列表中,所有的时间值必须是单调增加的。

在这里插入图片描述
另外,指定的沿必须是偶数个。waveform选项指定1个时钟周期内的波形,之后就是自我重复


If no waveform option is specified, the default is:
在这里插入图片描述

Here is an example of a clock specification with no waveform specification
(see Figure 7-3).
在这里插入图片描述
这个规范中,因为发有指定-name选项,时钟的名字就和端口的名字一-样,都是SCAN_CLK。
在这里插入图片描述


下面是另一个时钟规范的例子,波形的沿在周期的中间(如图7-4所示)。
在这里插入图片描述
时钟的名字是BDYCLK,被定义在端口GBLCLK。在实际操作中,让时钟的名字和端口的名字保持一致是个好主意。
下面是更多的时钟规范。
在这里插入图片描述


在这里插入图片描述
指定了第1个上升沿和下一个下降沿。在0.375ns处的下降沿是自动推理出的。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


   除了上面的属性以外,也可以选择性设置时钟源头的转换时间(转换率)。在某些情况下,比如某些PLL(Phase-locked Loop,锁相环。通常在ASIC中使用来生成高频率时钟。)的输出或者输入端口,工具不能自动计算出转换时间。在这种情况下,

   在时钟的源头明确指定转换时间是很有用的。要通过约束set_clock_transition来指定。
在这里插入图片描述

该约束只对理想时钟起作用,当时钟树构建完成就无视这一约束了,将会使用时钟引脚上的真实转换时间。如果时钟定义在一个输入端口、使用set_input_transition(见7.7节)约束来定义时钟上的转换率。


7.2.1 时钟不确定性(Clock Uncertainty)

   时钟的不确定性可以用 set_clock_uncertainty 约束来指定。不确定性可以用来对减少有效时钟周期的各种因素建模。这些因素可以是时钟抖动或者任何在时序分析中考虑的悲观项。
在这里插入图片描述
   注意,如图7.7所示,建立时间的时钟不确定性有效地减少了指定量的可用时钟周期。对保持时间检查,保持时间的时钟不确定性是需要满足的额外时序余量。

在这里插入图片描述


   下面的命令指定了跨过指定时钟边界的路径的不确定性,叫做时钟间不确定性(Inter-clock Uncertainty)。
在这里插入图片描述


   图7-8表明了一条穿过两个不同时钟域SYS_CLK和CFG_CLK的路径。基上以上跨时钟不确定性约束,建立时间检查的不确定性是100ps,保持时间检查的不确定性是50ps。

在这里插入图片描述


7.2.2 Clock Latency(时钟延迟)

   时钟的延迟(Clock Latency)可以用命令set_clock_latency指定。
#在MAIN CLK.上的上升沿时钟延迟是1,8ns

set_clock_latency 1.8 -rise [get_clocks MAIN_CLK]

#在所有时钟上的下降沿时钟延迟是2.1ns

set_clock_latency 2.1 -fall [all_clocks]

#The -rise, -fall refer to the edge at the clock pin of a flip-flop.


   有两种时钟延迟:网络延迟(Network Latency)源延迟(Source Latency)
   网络延迟是指从时钟定义点(create_clock)触发器的时钟引脚的延迟。源延迟,也叫插入延迟(Insertion Delay),是从时钟的源头到时钟的定义点。源延迟可以是片上(On-chip)延迟,也可以是片外(Off-chip)延迟。图7-9说明了这两种情况。触发器时钟引脚上的总的时钟延迟是源延迟加上网络延迟。
在这里插入图片描述


# Specify a network latency (no -source option) of 0.8ns for rise, fall, max and min:
set_clock_latency 0.8 [get_clocks CLK_CONFIG]

# Specify a source latency:
set_clock_latency 1.9 -source [get_clocks SYS_CLK]

# Specify a min source latency:
set_clock_latency 0.851 -source -min [get_clocks CFG_CLK]

# Specify a max source latency:
set_clock_latency 1.322 -source -max [get_clocks CFG_CLK]

   源延迟和网络延迟的一个很重要的区别是,一旦设计的时钟树构建完成,网络延迟是可以忽略的(假设使用set_propagated_clock命令)。但是,即使时钟树构建完成了,源延迟也依然存在。网络延迟是在时钟树综合之前对时钟树延迟的估计。当时钟树综合完成,从时钟源到触发器的时钟引脚的总时钟延迟就是源延迟,加上从时钟定义点到触发器的时钟树真实延迟。
   生成时钟(Generated Clock)将在下一节描述,虚拟时钟会在7.9节中描述


7.3 Generated Clocks(生成时钟)

   生成时钟是从主时钟(Master Clock)派生出来的。主时钟是用约束create_clock来定义的。
   当设计中基于主时钟生成一个新时钟,这个新时钟就被定义成生成时钟。例如,如果有时钟的三分频电路,应该在电路的输出端定义一个生成时钟。这个定义是必需的,因为STA不知道时钟周期已经在分频逻辑的输出端改变了,更重要的是这个新时钟的周期是多少。
   图7-10的例子表明了主时钟CLKP的二分频生成时钟。
在这里插入图片描述


create_clock -name CLKP 10 [get_pins UPLL0/CLKOUT]
# Create a master clock with name CLKP of period 10ns with 50% duty cycle at the CLKOUT pin of the PLL.
create_generated_clock -name CLKPDIV2 -source UPLL0/CLKOUT \ -divide_by 2 [get_pins UFF0/Q]
# Creates a generated clock with name CLKPDIV2 at the Q pin of flip-flop UFF0. The master clock is at the CLKOUT
# 在触发器UFF0的Q引脚,创建一个生成时钟CLKPDIV2
# pin of PLL. And the period of the generated clock is double
#主时钟在PLL的CLKOUT引脚。生成时钟的周期是时钟CLKP的2倍
# that of the clock CLKP, that is, 20ns.

   可以在触发器的输出端定义一个主时钟而不是生成时钟么?答案是可以,这确实是可能的。但是,这里有些缺点。定义一个主时钟而不是一个生成时钟,会创建一个新的时钟域。通常这并不是问题,只不过要在设置STA约束时处理更多的时钟域。把一个新时钟定义成生成时钟就不会创建新的时钟域。生成时钟不需要进行额外的约束。所以,应该尝试把内部生成的时钟定义为一个生成时钟,而不是决定把它声明成一个新的主时钟。
   主时钟和生成时钟的另一个重要不同是时钟源头这一概念。对于主时钟,时钟的源头在于主时钟的定义点。对于生成时钟,时钟的源头在于主时钟,而不是生成时钟。这意味着在时钟路径报告中,时钟路径的起点永远都是主时钟的定义点。这就是定义生成时钟而不是义新的主时钟的巨大优势,因为新的主时钟不会自动把源延迟计算进来。

   图7-11所示的例子中,多路复用器(Multiplexer)在两个输入端都有时钟。在这种情况下,没必要在多路复用器的输出端定义时钟。如果选择信号是常量,多路复用器的输出端自动得到了正确传播的时钟。如果多路复用器的选择引脚没有被约束,出于STA的目的,两个时钟都要经过多路复用器传播。在这种情况下,STA可能会报告TCLK和TCLKDIV5之间的路径。注意,这种路径是不可能存在的,因为选择线只能选择多路复用器的1个输入。在这种情况下,或许需要设置伪路径(False Path)或者指定两个时钟之间的互斥关系,进面避免报告不正确的路径。当然,这里假设在设计的其他地方没有TCLK和TCLKDIV5之间的路径。

在这里插入图片描述


   如果多路复用器的选择信号不是静态的,在器件工作时可以改变,这将会发生什么?在这种情况下,需要对多路复用器的输入进行时钟门控检查。时钟门控检查在第10章中有解释;这些检查确保多路复用器输入端的时钟会按照多路复用器的选择信号安全的切换。
   图7-12所示的例子中时钟SYS_CLK被一个触发器的输出端门控。因为触发器的输出端可能不是常量,处理这种情况的一个方法是在与门单元的输出端定义一个生成时钟,该时钟与输入时钟相同。

create_clock 0.1 [get_ports SYS_CLK]
# Create a master clock of period 100ps with 50% duty cycle.
create_generated_clock -name CORE_CLK -divide_by 1 \ -source SYS_CLK [get_pins UAND1/Z]
# Create a generated clock called CORE_CLK at the output of the and cell and the clock waveform is same as that of the master clock.
# 在与门单元的输出端创建生成时钟CORE_CLK,时钟波形和主时钟一致

在这里插入图片描述


   下一个例子是一个生成时钟的频率比源时钟高。图7-13展示了波形图。

create_clock -period 10 -waveform {0 5} [get_ports PCLK]
# Create a master clock with name PCLK of period 10ns with rise edge at 0ns and fall edge at 5ns.
# #创建一个主时钟PCLK,周期10ns,上升沿在0ns,下降沿在5ns。
create_generated_clock -name PCLKx2 \ -source [get_ports PCLK] \ -multiply_by 2 [get_pins UCLKMULTREG/Q]
# Creates a generated clock called PCLKx2 from the master clock PCLK and the frequency is double that of the master clock. The generated clock is defined at the output of the flip-flop UCLKMULTREG.
# 依据主时钟PCLK创建1个生成时钟PCLKx2,频率是主时钟的2倍。生成时钟定义在触发器 UCLKMULTREG的输出端。

在这里插入图片描述
   注意,选项-multiply_by和-divide_by指的是时钟的频率,即使主时钟定义了时钟周期。


7.3.1 Example of Master Clock at Clock Gating Cell Output(时钟门控单元输出端上的主时钟实例)

   思考图7-14所示的时钟门控例子。两个时钟输入进一个与门单元。问题来了,在该与门单元输出端是哪个时钟?如果与门单元的输入都是时钟,那就可以安全的在与门单元的输出定义一个新的主时钟,因为很可能该单元的输出和任一输入时钟都没有相位关系。

create_clock -name SYS_CLK -period 4 -waveform {0 2} \ [get_pins UFFSYS/Q]
create_clock -name CORE_CLK -period 12 -waveform {0 4} \ [get_pins UFFCORE/Q]
create_clock -name MAIN_CLK -period 12 -waveform {0 2} \ [get_pins UAND2/Z]
# Create a master clock instead of a generated clock
# at the output of the and cell.
# 在与门单元的输出端创建一个主时钟而不是一个生成时钟。

在这里插入图片描述


Generated Clock using Edge and Edge_shift Options

   在内部引脚创建时钟的一个缺点是影响路径延迟的计算,这要求设计者手动计算源延迟。
   图7-15展示了一个生成时钟的例子。生成了一个二分频时钟和两个有相位差(out-of-phase)的时钟。图中也展示了时钟的波形。
   例子中这些时钟的定义也在下面给出。生成时钟的定义演示了如何使用-edges选项,这是另一种定义生成时钟的方法。该选项用1组源主时钟的沿(rise,fall,rise)来构成新的生成时钟。主时钟的第1个上升沿就是沿1,第1个下降沿就是沿2,下一个上升沿就是沿3,以此类推。
在这里插入图片描述

create_clock 2 [get_ports DCLK]
# Name of clock is DCLK, has period of 2ns with a rise edge at 0ns and a fall edge at 1ns.

create_generated_clock -name DCLKDIV2 -edges {2 4 6} \ -source DCLK [get_pins UBUF2/Z]
# 生成时钟DCLKDIV2定义在缓冲器的输出端
# 它的波形是上升沿在源时钟的沿2,下降沿在源时钟的沿4
# 下一个上升沿在源时钟的沿6

create_generated_clock -name PH0CLK -edges {3 4 7} \ -source DCLK [get_pins UAND0/Z]
# The generated clock PH0CLK is formed using
# the 3, 4, 7 edges of the source clock.
# 生成时钟PH0CLK是用源时钟的沿3,4,7组成

create_generated_clock -name PH1CLK -edges {1 2 5} \ -source DCLK [get_pins UAND1/Z]
# The generated clock with name PH1CLK is defined at the output of the and cell and is formed with edges 1, 2 and 5 of the source clock.
# 生成时钟PH1CLK定义在与门单元的输出端,是用源时钟的沿1、2和5组成。

   如果生成时钟的第1个沿是下降沿呢?思考图7-16所示的生成时钟G3CLK。该生成时钟可以通过指定沿5、7和10来定义,如下面的时钟约束所示。在1ns(2号沿)处的下降沿可以自动推算出。
在这里插入图片描述

create_generated_clock -name G3CLK -edges {5 7 10} \ -source DCLK [get_pins UAND0/Z]

选项-edge_shift可以和选项-edge配合使用,使相应的沿偏移,形成新的生成波形。它指定了沿列表中每个沿偏移的量(以时间为单位)。下面是使用这些选项的例子。

create_clock -period 10 -waveform {0 5} [get_ports MIICLK]
create_generated_clock -name MIICLKDIV2 -source MIICLK \ -edges {1 3 5} [get_pins UMIICLKREG/Q]
# Create a divide-by-2 clock.
# 创建一个二分频时钟

create_generated_clock -name MIIDIV2 -source MIICLK \ -edges {1 1 5} -edge_shift {0 5 0} [get_pins UMIIDIV/Q]
# Creates a divide-by-2 clock with a duty cycle different from the source clock's value of 50%.
# 创建一个二分频时钟,但是占空比和源时钟的50%不同。

   沿列表中的沿排列必须是非降序(Non-decreasing)排列,但是同一沿可以使用两次,进而实现时钟脉冲独立于源时钟的占空比。上面例子中的-edge_shift近选项指明将源时钟的沿1移动0ns得到第1个沿,将源时钟的沿1移动5s得到第2个沿,将源时钟的沿5移动0ms得到第3个沿。图7-17展示了波形。
在这里插入图片描述


7.3.2 使用invert选项生成时钟(Generated Clock using Invert Option)

   下面是另一个生成时钟的例子;该例子使用了-invert选项。

create_clock -period 10 [get_ports CLK]
create_generated_clock -name NCLKDIV2 -divide_by 2 -invert \ -source CLK [get_pins UINVQ/Z]

   这个-invert选项在所有其他生成时钟选项生效后,使生成时钟反相。图7-18展示了生成这样反相时钟的原理图。
在这里插入图片描述


7.3.3 Clock Latency for Generated Clocks(生成时钟的时钟延迟)

   可以为生成时钟指定时钟延迟。指定在生成时钟上的源延迟,指定了从主时钟定义点到生成时钟定义点的延迟。所以,被一个生成时钟驱动的触发器时钟引脚上的总时钟延迟,是主时钟源延迟,生成时钟源延迟和生成时钟网络延迟之和。如图7-19所示。
在这里插入图片描述
   一个生成时钟可以把另一个生成时钟当作它的源,也就是说,存在有生成时钟的生成时钟,以此类推。但是,一个生成时钟只能有一个主时钟。更多生成时钟的例子在之后的小节中有描述。

7.3.4典型的时钟生成场景(Typical Clock Generation Scenario)

   图7-20展示了一种场景,在典型ASIC中时钟分配是如何进行的。晶振(Oscillator)位于芯片外部,生成一个低频率(典型值为10-50MHz)时钟,该时钟被芯片上的PLL当作参考时钟生成了一个高频率低抖动(Low-jitter)的时钟 (典型值为200~800MHz)。这个PLL时钟输入到一个时钟分频逻辑,然后生成了ASIC需要的时钟。
在这里插入图片描述


   在时钟分配的一些分支上,可能存在时钟门控(Clock Gate),它被用来关闭设计中不活跃部分的时钟,以在需要时节省功耗。PLL也可以在输出端连接一个多路复用器,以便在需要时绕过PLL。
   在参考时钟进入芯片的输入引脚处,为参考时钟定义了一个主时钟,第2个主时钟定义在PLL的输出端。PLL输出端的时钟和参考时钟没有相位关系。所以,输出时钟不应该是参考时钟的生成时钟。更常见的情况下,所有时钟分频器逻辑产生的时钟都被指定为是PLL输出端主时钟的生成时钟。


7.4约束输入路径(Constraining Input Paths)

   本节将描述输入路径的约束。这里需要强调一个重点,STA不能检查没有约束的路径上的任何时序。所以,任何路径都应该被约束,才能被分析。在之后几章里会介绍一些例子,其中一些逻辑可能我们并不关心,那就可以不约束相关的输入。例如,我们可能不在意那些严格控制信号的输入时序,所以可以决定没必要进行本节中描述的那些检查。但是,本节假设我们想要约束输入路径。
   图7-21展示了DUA的一条输入路径。触发器UFFO在设计的外部,为设计内部的触发器UFFI提供数据。数据通过输入端口INP1连接。
在这里插入图片描述


   时钟CLKA的定义指明了时钟周期,也就是在两个触发器UFF0和UFF1之间总的可用时间。外部逻辑所用时间为Tclk2q(发射触发器UFF0的CK到Q的延迟),加上Tc1(通过外部组合逻辑的延迟)。所以,延迟约束在输入引脚INP1定义了外部延迟Tclk2q加上TC1。在这个例子里,指定的延迟是相对于时钟CLKA的。

   下面是输入延迟约束。

set Tclk2q 0.9
set Tc1 0.6
set_input_delay -clock CLKA -max [expr Tclk2q + Tc1] \ [get_ports INP1]

   该约束指定了在输入INP1的外部延迟是1.5ns, 该延迟是相对于时钟CLKA的。假设CLKA的时钟周期是2ns, 引脚INP1的逻辑在设计内部传播只有500ps(=2ns-1.5ns)可用了。该输入延迟规范映射到输入约束上就意味着,Tc2加上UFF1的Tsetup必须小于500ps,这样触发器UFF1才可以可靠的捕获到触发器UFFO发射出来的数据。注意,上面的外部延迟指定的是最大值。

   让我们思考一种情况,我们必须同时考虑最大和最小延迟,如图7-22所示。下面是这个例子的约束。
在这里插入图片描述

create_clock -period 15 -waveform {5 12} [get_ports CLKP]
set_input_delay -clock CLKP -max 6.7 [get_ports INPA]
set_input_delay -clock CLKP -min 3.0 [get_ports INPA]

   INPA的最大最小延迟是从CLKP到INPA的延迟计算得到的。最大和最小延迟分别对应着最长和最短路径。通常情况下也对应着最坏情况慢速(最大时序工艺角)和最佳情况快速(最小时序工艺角)。所以,最大延迟对应着最大时序工艺角下的最长路径,最小延迟对应着最小时序工艺角下的最短路径。在我们的例子里,Tck2q的最大和最小延迟值分别是1.1ns和0.8ns。组合逻辑路径延迟Tc1的最大延迟5.6ns和最小延迟2.2ns。在INPA上的波形表明了数据到达设计输入并且期望保持稳定的时间窗口。从CLKP到INPA的最大延迟是(1.1ns+5.6ns)=6.7ns。最小延迟是(0.8ns+2.2ns)=3ns。这些指定的延迟是对应时钟有效沿的。考虑到外部输入延迟,设计内部的可用建立时间最小是在慢速工艺角的(15ns-6.7ns)=8.3ns,快速工艺角的(15ns-3.0ns)=12ns。所以,8.3ns是在DUA内部可靠捕获数据的可用时间。

   下面还有一些输入约束的例子。

set_input_delay -clock clk_core 0.5 [get_ports bist_mode]
set_input_delay -clock clk_core 0.5 [get_ports sad_state]

   因为没有指定-max和-min选项,500ps的值会应用到最大和最小延迟上。这个外部输入延迟是对应时钟clk_core的上升沿指定的。(如果输入延迟是对应时钟下降沿指定的,就必须使用-clock_fall选项)


7.5约束输出路径(Constraining Output Paths)

本节用下面3个例子讲解了输入路径的约束。

Example A

   图7-23所示的例子是经过DUA的输出端口的路径。Tc1和Tc2是经过组合逻辑的延迟。
   时钟CLKQ的周期定义了从触发器UFF0到触发器UFF1的总可用时间。外部逻辑的总延迟是Tc2加上Tsetup。这个总的延迟,Tc2+Tsetup,必须指定为输出延迟约束的一部分。注意,输出延迟是对应捕获时钟指定的。数据必须及时到达外部触发器UFF1,以满足建立时间的要求。
在这里插入图片描述

set Tc2 3.9
set Tsetup 1.1
set_output_delay -clock CLKQ -max [expr Tc2 + Tsetup] \ [get_ports OUTB]

这指定了对应时钟沿的最大外部延迟是Tc2加上Tsetup, 应该相当于延迟5ns。最小延迟也可以用类似方法指定。


Example B

   图7-24中的例子有最大和最小延迟。最大路径延迟是7.4ns(即最大Tc2加上Tsetup,为7+0.4)。最小路径延迟是-0.2ns(即最小Tc2减去Thold,为0-0.2)。所以输出约束如下:

create_clock -period 20 -waveform {0 15} [get_ports CLKQ]
set_output_delay -clock CLKQ -min -0.2 [get_ports OUTC]
set_output_delay -clock CLKQ -max 7.4 [get_ports OUTC]

在这里插入图片描述
   图7.24所示的波形表明OUTC何时必须保持稳定,确保可以被外部触发器可靠的捕获。
   该图描述了数据必须在要求的稳定区间之前就在输出端口准备好,而且要在稳定区间结束前保持稳定。这映射了DUA内部逻辑到输出端口OUTC的时序要求。


Example C

   这里是另一个说明输入输出约束的例子。这个模块有两个输入,DATAIN和MCLK,1个输出DATAOUT。图7-25所示为预期的波形。

reate_clock -period 100 -waveform {5 55} [get_ports MCLK]
set_input_delay 25 -max -clock MCLK [get_ports DATAIN]
set_input_delay 5 -min -clock MCLK [get_ports DATAIN]
set_output_delay 20 -max -clock MCLK [get_ports DATAOUT]
set_output_delay -5 -min -clock MCLK [get_ports DATAOUT]

在这里插入图片描述


7.6 时序路径组(Timing Path Groups)

   设计中的时序路径可以被当作路径的集合。每条路径都有一个起点和一个终点。图7-26所示为一些示例路径。
在这里插入图片描述
   在STA时,路径是依据有效的起点和有效的终点来记录的。有效的起点包括:输入端口,同步器件的时钟引脚,比如触发器和存储器。有效的终点是输出端口,同步器件的数据输入引脚。所以,一条有效的时序路径可以是:

i. from an input port to an output port,
ii. from an input port to an input of a flip-flop or a memory,
iii. from the clock pin of a flip-flop or a memory to an input of flipflop or a memory,
iv. from the clock pin of a flip-flop to an output port,
v. from the clock pin of a memory to an output port, and so on.

1)从输入端口到输出端口;
2)从输入端口到触发器或存储器的输入;
3)从触发器或存储器的时钟引脚到触发器或存储器的输入;
4)从触发器的时钟引脚到输出;
5)从存储器的时钟引脚到输出端口,诸如此类。

   图7-26中的有效路径是

• input port A to UFFA/D,
• input port A to output port Z,
• UFFA/CLK to UFFB/D, and
• UFFB/CLK to output port Z.

1)输入端口A到UFFA/D;
2)输入端口A到输出端口Z;
3)UFFA/CK到UFFB/D;
4)UFFB/CK到输出端口Z。

   时序路径可以根据路径终点相关的时钟被分为不同的路径组(Path Group)。所以,每个时钟都有一组和它相关的路径。也会有默认路径组,它包括了所有非时钟(异步)路径。

   在图7-27所示的例子中,路径组是

  • 1)CLKA组:输入端口A到UFFA/D;
  • 2)CLKB组:UFFA/CK到UFFB/D;
  • 3)默认组:输入端口A到输出端口Z,UFFB/CK到输出端口Z.
• CLKA group: Input port A to UFFA/D.
• CLKB group: UFFA/CK to UFFB/D.
• DEFAULT group: Input port A to output port Z, UFFB/CK to output port Z.

   静态时序分析和报告通常是在每个路径组分别进行的。
在这里插入图片描述


7.7外部属性建模(Modeling of External Attributes)

   命令create_clock、set_input_delay和set_output_delay已经足够约束芯片内的所有路径并进行时序分析了,但它们还不够得到模块IO引脚的精确时序。就需要下面的属性来精确建模设计的环境。对于输入,需要在输入指定转换率。该信息可以用以下命令提供:

• set_drive(This command is obsolete and not recommended)
• set_driving_cell
• set_input_transition

   对于输出,需要指定输出看到的电容性负载。该信息可以用以下命令指定:set_load

7.7.1 驱动能力建模(Modeling Drive Strengths)

   命令set_drive和set_driving_cell是用来对外部源的驱动能力建模,该外部源驱动模块的输入端口。如果没有这些约束,默认情况下,所有的输入假设拥有无限的驱动能力。这种默认情况意味着输入引脚的转换时间是0。
   命令set_drive在DUA的输入引脚明确指定了驱动电阻的值。这个电阻值越小,驱动能力越强。电阻值为0意味着无限的驱动能力。

set_drive 100 UCLK
# Specifies a drive resistance of 100 on input UCLK.
# 在输入UCLK指定驱动电阻为100。
#上升驱动和下降驱动不同:
# Rise drive is different from fall drive:
set drive -rise 3 [all inputs]
set drive -fall 2 [all_inputs]

   一个输入引脚的驱动能力是用来计算在第1个单元上的转换时间的。指定的驱动值也被用来计算存在任何RC互连参数情况下,从输入端口到第1个单元的延迟。

Delay_to_first_gate = (drive * load_on_net) + interconnect_delay

   约束set_driving_cell提供了描述端口驱动能力的更保守和精确的方法。命令set_driving_cell可以被用来指定一个单元来驱动输入端口。
在这里插入图片描述


set_driving_cell -lib_cell INV3  -library slow [get_ports INPB]
# The input INPB is driven by an INV3 cell from library slow.
# 输入INPB是由库文件s1ow中的INV3单元驱动的。

set_driving_cell -lib_cell INV2  -library tech13g [all_inputs]
# Specifies that the cell INV2 from a library tech13g is the driving cell for all inputs.
# 指定库文件tech13g中的单元IWV2驱动所有的输入

set_driving_cell -lib_cell BUFFD4 -library tech90gwc  [get_ports {testmode[3]}]
# The input testmode[3] is driven by a BUFFD4 cell from library tech90gwc.
# 输入testmode[3]是由库文件tech90gwc中的单元BUFFD4驱动的。

   像驱动约束一样,输入端口的驱动单元被用来计算在第1个单元上的转换时间,和计算存在任何RC互连参数情况下,从输入端口到第1个单元的延迟。
   约束set_driving_cell需要注意的一点是,驱动单元由于电容性负载带来输入端口的增加延迟,被包括进输入的额外延迟。
   作为上述方法的替代方法,约束set_input_transition提供了一种在输入端口指定转换率的方便的方法。也可以选择性指定参考时钟。下面是图7-30所示例子的约束,以及其他一些例子。
在这里插入图片描述


set_input_transition 0.85 [get_ports INPC]
# Specifies an input transition of 850ps on port INPC.
# 在端口INPC中指定输入转换时间为850ps。

set_input_transition 0.6 [all_inputs]
# Specifies a transition of 600ps on all input ports.
# 在所有输入端口指定转换时间为600ps。

set_input_transition 0.25 [get_ports SD_DIN*]
# Specifies a transition of 250ps on all ports with pattern SD_DIN*.
# Min and max values can optionally be specified using the -min and -max options.
# 指定所有名字匹配SD DIN*的端口转换时间为250ps.可以用选项-min和-max来分别指定最小和最大值。

   综上所述,需要输入端口的转换率来决定输入路径上第1个单元的延迟。如果没有该约束,就假设理想的转换时间为0,这很可能是无法实现的。


7.7.2 电容负载建模(Modeling Capacitive Load)

    约束set_load在输出端口设置了电容性负载,如图7-31所示,以此对输出端口驱动的外部负载建模。默认情况下,在端口的电容性负载为0。该负载可以被指定为明确的电容值,或者是一个单元的输入引脚电容。
在这里插入图片描述


set_load 5 [get_ports OUTX]
# Places a 5pF load on output port OUTX.
# 在输出端口OUTX指定5pF的负载

set_load 25 [all_outputs]
# Sets 25pF load capacitance on all outputs.
# 在所有输出端指定25pF的负载电容


set_load -pin_load 0.007 [get_ports {shift_write[31]}]
# Place 7fF pin load on the specified output port.
# A load on the net connected to the port can be specified using the -wire_load option.
# If neither -pin_load nor -wire_load option is used, the default is the -pin_load option.

# 在指定的输出端口指定7fF的引脚负载。
# 可以用-wire load选项指定端口连接的线的负载。
# 如果设有使用-pin load和-wire_load选项,默认是-pin_load。

   指定输出的负载是很重要的,因为该值影响驱动输出的单元的延迟。如果没有该约束,就假设负载为0,这很可能是无法实现的。
   约束set_load也可以用来指定1条设计内部线的负载。下面是一个例子。

set_load 0.25 [get_nets UCNT5/NET6]
# Sets the net capacitance to be 0.25pF.

7.8设计规则检查(Design Rule Checks)

   在STA中两个常用的设计规则是最大转换时间(Max Transition)最大电容(Max Capacitance)。这些规则会检查设计内所有的端口和引脚都满足指定的转换时间范围和电容范围。这些范围可以用下面的命令来指定:

• set_max_transition
• set_max_capacitance

   作为STA的一部分,任何违反这些设计规则的违例都会以裕量(Slack)的形式被报告出来。下面是一些例子。

set_max_transition 0.6 IOBANK
# Sets a limit of 600ps on IOBANK.

set_max_capacitance 0.5 [current_design]
# Max capacitance is set to 0.5pf on all nets in current design.
# 在当前设计中设定所有线的最大电容为0.5pf

   一条线的电容是所有引脚的电容,加上任何IO的负载,加上该线任何互连电容的总和。图7-32展示了一个例子。

Total cap on net N1 =
pin cap of UBUF1:pin/A +
pin cap of UOR2:pin/B +
load cap specified on output port OUTP +
wire/routing cap
= 0.05 + 0.03 + 0.07 + 0.02
= 0.17pF

Total cap on net N2 =
pin cap of UBUF2/A +
wire/routing cap from input to buffer
= 0.04 + 0.03
= 0.07pF

在这里插入图片描述


   转换时间计算是延迟计算的一部分。例如图7-32。(假设单元UBUF2使用线性延迟模型)

Transition time on pin UBUF2/A =
drive of 21 * total cap on net N2
= 2 * 0.07 = 0.14ns = 140ps

Transition time on output port OUTP =
drive resistance of UBUF2/Z * total cap of net N1 =
1 * 0.17 = 0.17ns = 170ps

   也可以为设计指定其他的设计规则检查。比如说:set_max_fanout(指定设计中所有引脚的最大扇出值),set_max_area(约束设计);但是这些检查是约束综合而不是STA。


7.9虚拟时钟(Virtual Clocks)

   虚拟时钟(Virtual Clocks)是一个存在的时钟,但是和设计的任何引脚或者端口都不相关。它被用来在STA中当作参考时钟,指定相对于时钟的输入输出延迟。图7-33所示的例子就是虚拟时钟。DUA从CLK_CORE得到它的时钟,但是驱动输入端口ROW_IN的时钟是CLK_SAD。在这种情况下,如何指定输入端口ROW_IN的IO约束呢?同样的问题也发生在输出端口STATE_0。
在这里插入图片描述


   为了处理这种情况,可以定义没有源端口或源引脚的虚拟时钟。在图7-33中的例子,可以为时钟CLK_SAD和CLK_CFG定义虚拟时钟。

create_clock -name VIRTUAL_CLK_SAD -period 10 -waveform {2 8}
create_clock -name VIRTUAL_CLK_CFG -period 8  -waveform {0 4}
create_clock -period 10 [get_ports CLK_CORE]

定义好虚拟时钟后,就可以相对于这些虚拟时钟指定IO约束。

```bash
set_input_delay -clock VIRTUAL_CLK_SAD -max 2.7 \
[get_ports ROW_IN]

set_output_delay -clock VIRTUAL_CLK_CFG -max 4.5 \
[get_ports STATE_O]

图7-34说明了这些输入路径的时序关系。DUA的输入路径被约束为5.3s或者更少。
在这里插入图片描述


   图7-35说明了这些输出路径的时序关系。DUA的输出路径被约束为3.5s或者更少。
在这里插入图片描述
   选项-min在set_input_delay和set_output_delay约束中用来验证最快(或者最小)路径。虚拟时钟的使用只是一种约束输入和输出(IO)的方法,设计者也可以选取其他的方法来约束IO。


7.10 Refining the Timing Analysis(完善时序分析)

用于约束分析空间的4个常见命令是:
1)set_case_analysis:在单元输入引脚或者输入端口指定常量;
2)set_disable_timing:中断单元的时序弧;
3)set_false_path:指定路径不是真实的,表明这些路径不需要在STA中检查;
4)set_multicycle_path:指定路径可以有大于1个时钟周期。
约束set_false_path和set_multicycle_path会在第8章有详细的讨论。

7.10.1 Specifying Inactive Signals(指定无效信号)

   在设计中,在芯片的指定模式下某些信号是常量。例如,如果芯片有DFT逻辑,那在普通的功能模式下,芯片的TEST引脚就应该为0。给STA指定常量通常是很有用的。这会帮助减少分析空间,不报出任何不相关的路径。例如,如果TEST引脚不设为常量,可能存在一些奇怪的长路径本该在功能模式下永远不存在。这些常量信号用约束set_case_analysis来指定。

set_case_analysis 0 TEST

set_case_analysis 0 [get_ports {testmode[3]}]
set_case_analysis 0 [get_ports {testmode[2]}]
set_case_analysis 0 [get_ports {testmode[1]}]
set_case_analysis 0 [get_ports {testmode[0]}]

   如果设计有多个功能模式且只需要分析其中一个功能模式,则可以用情况分析来指定需要分析的真正模式。

set_case_analysis 1 func_mode[0]
set_case_analysis 0 func_mode[1]
set_case_analysis 1 func_mode[2]

   注意情况分析可以指定在设计的任一引脚上。另一个常见的情况分析应用是,当设计可以在多个时钟下运行,可以通过多路复用器来控制选择合适的时钟。为了让STA分析简化并减少CPU运行时间,让STA分别在不同的时钟选择下进行是很有益的。图7-36所示的例子说明了在不同设定下多路复用器选择不同的时钟。

在这里插入图片描述

set_case_analysis 1 UCORE/UMUX0/CLK_SEL[0]
set_case_analysis 1 UCORE/UMUX1/CLK_SEL[1]
set_case_analysis 0 UCORE/UMUX2/CLK_SEL[2]

   第1个set_case_analysis让MIICLK选择了PLLdiv16。PLLdiv8的时钟路径被阻断了,没有通过多路复用器传播。所以,没有时序路径是用时钟PLLdiv8分析(假设这个时钟没有在多路复用器之前到达任何触发器)。类似的,最后的set_case_analysis让ADCCLK选择了SCANCLK,CLK200的时钟路径被阻断了。


7.10.2中断单元内部的时序弧(Breaking Timing Arcs in Cells)

   每个单元都有从输入到输出的时序弧,1条时序路径可能穿过其中一条单元内时序孤。在某些情况下,可能穿过单元的特定路径不可能发生。例如,思考一种场景,时钟和多路复用器的选择端相连,而多路复用器的输出端又是数据路径的一部分。在这种情况下,中断多路复用器的选择引脚和输出引脚可能是很有用的。图7-37所示为这样的例子。经过多路复用器选择端的路径不是一条有效的路径。这样的时序弧可以用set_disable_timing中断。

set_disable_timing -from S -to Z [get_cells UMUX0]

在这里插入图片描述
   因为这个时序弧不再存在了,需要分析的时序路径相应地减少了。另一个类似用法的例子是禁止触发器的最小时钟脉冲宽度检查。
   使用set_disable_timing时要小心,因为它能删除所有经过指定引脚的时序路径。如果可以的话,最好使用命令set_false_path和set_case_analysis。


7.11点对点约束(Point-to-Point Specification)

   可以使用命令set_min_delay和set_max_delay来约束点对点(Point-to-Point Specification)路径。这些约束可以让出发点和到达点之间的路径延迟限定在约束指定值之内。该约束将覆盖路径上的任何默认单周期时序路径约束和多周期时序路径约束。
   命令set_max_delay指定了路径的最大延迟,命令set_min_delay制定了路径的最小延迟。

set_max_delay 5.0 -to UFF0/D
# All paths to D-pin of flip-flop should take 5ns max.
# 所有到触发器D引脚的路径延迟的极限是5ns

set_max_delay 0.6 -from UFF2/Q -to UFF3/D
# All paths between the two flip-flops should take a max of 600ps.
# 所有这2个触发器之间的路径延迟的极限是600ps

set_max_delay 0.45 -from UMUX0/Z -through UAND1/A -to UOR0/Z
# Sets max delay for the specified paths.
# 为指定路径设置最大延迟

set_min_delay 0.15 -from {UAND0/A UXOR1/B} -to {UMUX2/SEL}

   在上面的例子中,需要注意使用非标准的内部引脚作为起点和终点,会强制让这些点成为起始和终结点,也会把该点上的路径分割。
   可以指定类似的从一个时钟到另一个时钟的点到点约束。

set_max_delay 1.2 -from [get_clocks SYS_CLK] \
-to [get_clocks CFG_CLK]
# All paths between these two clock domains are restricted to a max of 1200ps.
# 两个时钟域之间的所有路径的最大延迟为1200ps。#两个时钟域之间的所有路径的最大延迟为1200ps。

set_min_delay 0.4 -from [get_clocks SYS_CLK] \ -to [get_clocks CFG_CLK]
# The min delay between any path between the two clock domains is specified as 400ps.
# 两个时钟域之间的所有路径的最小延迟为400ps。

   如果1条路径上有多个时序约束,比如时钟周期,set_max_delayset_min_delay,限制最紧的约束是永远要检查的。多个时序约束可能是先进行全局约束,然后进行局部约束造成的。


7.12 路径分割(Path Segmentation)

   把时序路径切割为被时序约束的较小的路径被称为路径分割。
   1条时序路径有1个起点和1个终点。路径上额外的起点和终点可以用命令set_input_delayset_output_delay来创建。命令set_input_delay通常在单元的输出引脚定义1个起点,而set_output_delay通常在单元的输入引脚定义1个新终点。这些约束定义的新时序路径,是原有时序路径的子集。
   思考图7-38所示的路径。一旦定义时钟SYSCLK, 被时序约束的路径是从UFF0/CK到UFF1/D。如果只对报告从UAND2/Z到UAND6/A的路径感兴趣,可以使用下面的两个命令:

set STARTPOINT [get_pins UAND2/Z]
set ENDPOINT [get_pins UAND6/A]
set_input_delay 0 $STARTPOINT
set_output_delay 0 $ENDPOINT

   定义上面这些约束让原有从UFF0/CK到UFF1/D的时序路径被分割,分别创造了新的内部起点和终点UAND2/Z和UAND6/A。新的时序报告会明确写出这条新路径:

   注意,两条额外的时序路径也自动创建了、一条是从UFF0/CK到UAND2/Z, 另一条是UAND6/A到UFF1/D。所以原有的时序路径被切割成了3个部分,每个部分都分别被时序约束。
在这里插入图片描述
命令set_disable_timing, set_max_delay 和 set_min_delay 也会造成时序路径被分割。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对8237 DUA控制器进行初始化,可以采取以下步骤: 1. 设置控制字寄存器(Command Word Register,CWR)。 控制字寄存器的格式为: Bit 0-2: 传输方式,01 表示单字节传输 Bit 3-4: 通道选择,00 表示通道 0 Bit 5-6: 存储器读写方向,01 表示写入存储器 Bit 7 : 内部/外部命令,0 表示内部命令 控制字寄存器的值为 00001001B,即 09H。 2. 设置模式寄存器(Mode Word Register,MWR)。 模式寄存器的格式为: Bit 0-1: 传输类型,00 表示单次传输 Bit 2-3: 自动初始化方式,00 表示不自动初始化 Bit 4-5: 传输方向,01 表示从外设读取数据 Bit 6-7: 传输速率,00 表示最高速率 模式寄存器的值为 00000101B,即 05H。 3. 设置外设地址寄存器(Address Register,AR)。 外设地址寄存器的值为 00H,表示使用通道 0。 4. 设置计数器寄存器(Counter Register,CR)。 计数器寄存器的值为 48,即 30H。 5. 启动传输。 启动传输需要向命令寄存器(Command Register,CR)写入 01H。 完整的初始化程序如下: ``` MOV DX, 0D04H ; 将 8237 DUA 控制器的基址端口地址 0D04H 存入 DX MOV AL, 09H ; 控制字寄存器的值为 09H OUT DX, AL ; 将控制字寄存器的值写入 8237 DUA 控制器的基址端口 INC DX ; 选择命令字寄存器 MOV AL, 01H ; 启动 DMA 传输 OUT DX, AL ; 将命令字寄存器的值写入 8237 DUA 控制器的基址端口 DEC DX ; 选择模式字寄存器 MOV AL, 05H ; 模式寄存器的值为 05H OUT DX, AL ; 将模式寄存器的值写入 8237 DUA 控制器的基址端口 DEC DX ; 选择外设地址寄存器 MOV AL, 00H ; 外设地址寄存器的值为 00H OUT DX, AL ; 将外设地址寄存器的值写入 8237 DUA 控制器的基址端口 DEC DX ; 选择计数器寄存器 MOV AL, 30H ; 计数器寄存器的值为 30H OUT DX, AL ; 将计数器寄存器的值写入 8237 DUA 控制器的基址端口 ``` 这样,就完成了对8237 DUA控制器的初始化,可以开始进行DMA传输了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值