第 8 章 时序验证(Timing Verification)

描述了时序检查,这个各种时序检查是作为各种时序分析的一部分执行。其中包括amongst others - setup、保持和异步恢复和移除检查。这些时序检查旨在彻底验证被分析设计的时序。

本章节将介绍静态时序分析所执行的一部分检查,这些检查旨在详尽地验证待分析设计的时序。

两个主要检查是建立时间检查和保持时间检查。一旦在触发器的时钟引脚上定义了时钟,就会自动推断出该触发器的建立时间检查和保持时间检查。时序检查通常在多种条件下执行,包括最坏情况下的慢速条件和最佳情况下的快速条件。通常,最坏情况下的慢速条件对于建立时间检查至关重要,而最佳情况下的快速条件对于保持时间检查至关重要-尽管保持时间检查也可能在最坏情况下的慢速条件下执行。

本章中给出的示例假设网络延迟为零;这样做是为了简单,不会改变本文提出的概念。

8.1 建立时间时序检查(Setup Timing Check)

建立时间检查(setup timing check)验证时钟和触发器的数据引脚之间的时序关系,以便满足建立时间要求。换句话说,建立时间检查确保数据在触发器输入之前在触发器的输入端可用。在时钟的有效边沿到达触发器之前,数据应该稳定一段时间,即触发器的建立时间。这一要求确保数据被可靠地捕获到触发器中。图 8-1 显示了典型触发器的建立时间要求。建立时间检查验证触发器的建立时间要求。

通常,有一个发起触发器(用于发起数据的触发器)和捕获触发器(用于捕获数据的触发器),这个捕获触发器的建立时间要求必须满足。建立时间检查将验证从发起触发器到捕获触发器的最长(或最大)路径,这两个触发器的时钟可以相同也可以不同。建立时间检查是从发起触发器中时钟的第一个有效沿到捕获触发器中时钟后面最接近的那个有效沿。建立时间检查将确保上一个时钟周期发起的数据准备好在一个周期后被捕获。

现在我们研究一个简单的示例,如图8-2所示,其中发起触发器和捕获触发器具有相同的时钟。时钟CLKM的第一个上升沿在Tlaunch时间后出现在发起触发器的时钟引脚上,由该时钟沿发起的数据出现在触发器UFF1的D引脚的所需时间为Tlaunch + Tck2q + Tdp。时钟CLKM的第二个上升沿(通常在一个周期后检查建立时间)出现在捕获触发器UFF1的时钟引脚上的时间为Tcycle + Tcapture。这两个时间之差必须大于触发器UFF1的建立时间要求,以确保触发器UFF1可靠地捕获数据。

建立时间检查可以用数学公式表示:

其中Tlaunch是发起触发器UFF0的时钟树延迟,Tdp是组合逻辑数据路径的延迟,Tcycle是时钟周期,Tcapture是捕获触发器UFF1的时钟树延迟。

换句话说,数据到达捕获触发器D引脚所花费的总时间必须小于时钟传输到捕获触发器所花费的时间加上时钟周期再减去建立时间要求。

由于建立时间检查受到-max的约束,因此建立时间检查始终使用最长或最大的时序路径。出于同样的原因,通常在延迟最大的慢工艺角(slow corner)下执行建立时间检查。

8.1.1 触发器到触发器路径(Flip-flop to Flip-flop Path)

以下是一份建立时间检查的路径报告:

该报告中显示发起触发器(由Startpoint指定)的实例名称为UFF0,由时钟CLKM的上升沿触发。捕获触发器(由Endpoint指定)为UFF1,也由时钟CLKM的上升沿触发。路径组(Path Group)显示它属于路径组CLKM。如上一章所述,设计中的所有路径都基于捕获触发器的时钟归类为路径组。路径类型(Path Type)显示此报告中的延迟均为最大路径延迟,表明这是建立时间检查。这是因为建立时间检查对应于通过逻辑的最大(或最长路径)延迟。注意,保持时间检查对应于通过逻辑的最小(或最短路径)延迟。

        Incr列显示了指定端口或引脚的单元或网络延迟增量,Path列显示了数据实际到达和需要到达的路径累积延迟,这是用于此示例的时钟约束:

create_clock -name CLKM -period 10 -waveform {0 5} \[get_ports CLKM]
set_clock_uncertainty -setup 0.3 [all_clocks]
set_clock_transition -rise 0.2 [all_clocks]
set_clock_transition -fall 0.15 [all_clocks]

启动路径( launch path)需要 0.26ns 才能到达触发器 UFF1 的 D 引脚 - 这是到达捕获触发器输入的时间。捕获边沿(建立时间检查时为一个周期)为10ns。为该时钟指定了 0.3ns 的时钟不确定性(clock uncertainty) - 因此,时钟周期减少了不确定性余量。时钟不确定性包括由于时钟源中的抖动( jitter )和用于分析的任何其他时序裕量而导致的周期时间变化。触发器的建立时间 0.04ns(称为库建立时间library setup time)从总捕获路径中扣除,产生所需的时间为 9.66ns。由于到达时间为 0.26ns,因此该时序路径上存在 9.41ns 的正裕量( positive
slack
)。请注意,所需时间和到达时间之间的差异可能看起来为 9.40 ns - 但实际值​​是 9.41 ns,出现在报告中。之所以存在异常,是因为报告仅显示小数点后两位,而内部计算和存储的值比报告的值具有更高的精度。

时序报告中的时钟网络延迟(clock network delay)是什么?为什么将其标记为ideal?时序报告中的这一行表明时钟树被认为是ideal的,时钟路径中的任何缓冲器(buffer)都假定为零延迟。一旦构建了时钟树,就可以将时钟网络标记为“propagated”,从而使得时钟路径显示实际延迟值,如下一个示例时序报告中所示:0.11ns延迟是发起时钟上的时钟网络延迟,而0.12ns延迟是捕获触发器上的时钟网络延迟。

时序路径报告可以选择包含扩展的时钟路径,即明确显示时钟树。这是一个这样的例子。

请注意,时钟缓冲器 UCKBUF0、UCKBUF1 和 UCKBUF2 出现在上面的路径报告中,并提供了如何计算时钟树延迟的详细信息。

如何计算第一个时钟单元 UCKBUF0 的延迟?如前几章所述,单元延迟是根据单元的输入转换时间和输出电容计算的。因此,问题是在时钟树中第一个单元的输入处使用什么转换时间。可以使用 set_input_transition 命令明确指定第一个时钟单元输入引脚上的转换时间(或转换)。

set_input_transition -rise 0.3 [get_ports CLKM]
set_input_transition -fall 0.45 [get_ports CLKM]

在上面显示的 set_input_transition 命令中,我们将输入上升转换时间指定为 0.3ns,将下降转换时间指定为 0.45ns。在没有输入转换命令的情况下,在时钟树的原点假设理想的转换,这意味着上升和下降转换时间都是 0ns。

时序报告中的“r”和“f”字符表示时钟或数据信号的上升沿(和下降沿)。上一个时序路径报告中显示了一条从UFF0 / Q的下降沿开始到UFF1 / D的上升沿结束的路径。由于UFF1 / D可以为0或1,因此也可以有一条路径在UFF1 / D的下降沿结束。以下就是这样一条路径:

注意,触发器时钟引脚的边沿(称为有效边沿active edge)保持不变。它只能是上升或下降有效沿,具体取决于触发器是由上升沿触发的还是由下降沿触发的。

什么是时钟源延迟(clock source latency)? 这也被称为插入延迟(insertion delay),是时钟从其源端传播到待分析设计的时钟定义点所花费的时间,如图8-3所示,这对应于设计之外的时钟树延迟。例如,如果该设计是较大模块的一部分,则时钟源延迟是指直到待分析设计时钟引脚为止的时钟树延迟。可以使用set_clock_latency命令明确指定此延迟。

set_clock_latency -source -rise 0.7 [get_clocks CLKM]
set_clock_latency -source -fall 0.65 [get_clocks CLKM]

如果没有这样的命令,则假定延迟为 0。这是早期路径报告中使用的假设。请注意,源延迟不会影响设计内部且具有相同启动时钟和捕获时钟的路径。这是因为相同的延迟被添加到启动时钟路径和捕获时钟路径。然而,这种延迟确实会影响经过分析设计的输入和输出的时序路径。

如果没有-source选项,则set_clock_latency命令将定义时钟网络延迟,这是从DUA中时钟定义点到触发器的时钟引脚的延迟。时钟网络延迟用于在建立时钟树之前(即在时钟树综合之前)对通过时钟路径的延迟进行建模。一旦建立了时钟树并标记为了“已传播”(propagated),便会忽略此时钟网络延迟约束。set_clock_latency命令也可用于对从主时钟到其衍生时钟的延迟进行建模,如7.3节所述。当时钟生成逻辑不是设计的一部分时,该命令也可用于建模片外时钟延迟。

8.1.2 触发器路径的输入(Input to Flip-flop Path)

这是通过输入端口到触发器的路径报告示例。图 8-4 显示了与输入路径和时钟波形相关的原理图。

首先要注意的是第一行中的input port clocked by VIRTUAL_CLKM。如7.9节中所述,该时钟可以被认为是驱动设计输入端口INA的虚拟触发器,该虚拟触发器的时钟为VIRTUAL_CLKM。此外,从该虚拟触发器的时钟引脚到输入端口INA的最大延迟指定为2.55ns,在报告中显示为input external delay。可以使用以下SDC命令指定这些参数:

create_clock -name VIRTUAL_CLKM -period 10 -waveform {0 5}set_input_delay -clock VIRTUAL_CLKM \
-max 2.55 [get_ports INA]

请注意,虚拟时钟VIRTUAL_CLKM的定义没有与设计中任何引脚相关,这是因为它是在设计之外定义的(它是虚拟的)。输入延迟约束set_input_delay指定了相对于虚拟时钟的延迟。

输入路径从端口INA开始,如何计算连接到端口INA的第一个单元UINV1的延迟呢?一种方法是指定输入端口INA的驱动单元,该驱动单元用于确定驱动强度,从而确定端口INA上的转换时间,然后用于计算单元UINV1的延迟。在输入端口INA上没有任何转换时间约束的情况下,将假定端口上的过渡时间是理想的,即过渡时间为0ns。

set_driving_cell -lib_cell BUFF \-library lib013lwc [get_ports INA]

图8-4还展示了如何进行建立时间检查。数据必须到达UFF2 / D的时间为9.85ns,但是数据实际到达的时间为2.65ns,因此该报告显示该路径的正裕量为7.2ns。

具有实际时钟的输入路径(Input Path with Actual Clock)

也可以根据实际时钟指定输入到达时间;这些不一定必须针对虚拟时钟进行指定。实际时钟的示例是设计中内部引脚或输入端口上的时钟。图 8-5 描述了一个示例,其中端口 CIN 上的输入约束是相对于输入端口 CLKP 上的时钟指定的。此约束指定为:

set_input_delay -clock CLKP -max 4.3 [get_ports CIN]

这里是这个约束对应的输入路径报告。

请注意,起始点(Startpoint)与预期一致,将输入端口的延迟参考时钟指定为了CLKP。

8.1.3 触发器到输出路径(Flip-flop to Output Path)

与上述输入端口约束类似,输出端口可以相对于虚拟时钟或设计的内部时钟、输入时钟端口或输出时钟端口受到约束。这是一个示例,显示了相对于虚拟时钟约束的输出引脚 ROUT。输出约束如下:

set_output_delay -clock VIRTUAL_CLKP \-max 5.1 [get_ports ROUT]
set_load 0.02 [get_ports ROUT]

为了确定最后一个单元连接到输出端口的延迟,需要指定该端口上的负载,上面使用了set_load命令来指定输出负载。请注意,端口ROUT可能在DUA内部具有负载,而set_load约束指定的是额外的负载,即来自DUA外部的负载。在没有set_load命令约束的情况下,将假定外部负载的值为0(这可能不现实,因为该设计很可能会在其它设计中使用)。下图8-6显示了具有虚拟时钟的虚拟触发器的时序路径:

通过输出端口的路径报告如下所示。

注意,指定的输出延迟在报告中显示为output external delay,其作用类似于虚拟触发器所需的建立时间。

8.1.4 输入到输出路径(Input to Output Path)

设计也可以具有从输入端口到输出端口的纯组合逻辑路径。可以像我们前面看到的输入和输出路径一样,对路径进行约束和时序分析。下图8-7显示了这种路径的一个示例,虚拟时钟同时用于指定输入和输出端口上的约束。

以下是输入和输出延迟约束:

set_input_delay -clock VIRTUAL_CLKM \-max 3.6 [get_ports INB]
set_output_delay -clock VIRTUAL_CLKM \-max 5.8 [get_ports POUT]

以下是一个时序路径报告,它经过从输入INB到输出POUT的组合逻辑。请注意,任何内部时钟延迟(如果存在)都不会对该路径报告产生影响。

8.1.5 频率直方图(Frequency Histogram)

如果要绘制一个典型设计的建立时间裕量与路径数的频率直方图,则如图8-8所示。根据设计的状态(是否进行了优化) ,对于未优化的设计,零裕量(zero slack)线将更靠近右侧,而对于优化后的设计则更趋向于左侧。对于没有时序违例的设计(即没有路径的裕度为负),整个曲线将在零裕量线的右侧。

这是一个以文本形式显示的直方图,通常可以由静态时序分析工具生成。

前两个索引表示裕量的范围,第三个索引是该裕量范围内的路径数,例如,有941条路径的裕量范围为410ps至415ps。直方图表明该设计没有时序违例的路径,即所有路径均具有正的裕量,而关键路径的裕量值在375ps至380ps之间。

难以满足时序要求的设计会使直方图的驼峰向左偏大,也就是说,许多路径的裕量值接近于零。通过观察频率直方图可以得出的另一结果是:可以进一步优化设计以实现零裕量的可能性,即时序收敛有多困难。如果违例路径的数量少并且负裕量值也很小,则设计相对比较容易满足所需的时序。但是,如果违例路径的数量很大并且负裕量值也很大,则这意味着设计将需要付出很大努力才能满足所需的时序。

8.2 保持时间检查(Hold Timing Check)

  保持时间检查确保正在改变的触发器输出值不会传递到捕获触发器并在触发器有机会捕获其原始值之前覆盖其输出。此检查基于触发器的保持要求。触发器的保持约束要求被锁存的数据应该在时钟的有效边沿之后的指定时间内保持稳定。图 8-9 显示了典型触发器的保持要求。

就像建立时间检查一样,保持时间检查是在发起触发器(发起数据的触发器)和捕获触发器(捕获数据的触发器以及必须满足其保持时间要求的触发器)之间进行保持时间检查的。这两个触发器的时钟可以相同也可以不同。保持检查是从启动触发器时钟的一个有效边沿到捕获触发器的同一时钟边沿。因此,保持检查与时钟周期无关。保持检查在捕获触发器时钟的每个有效边沿上执行。

现在我们来看一个简单的示例,如图8-10所示,其中发起触发器和捕获触发器具有相同的时钟。

考虑时钟CLKM的第二个上升沿。时钟上升沿发起的数据需要Tlaunch + Tck2q + Tdp时间到达捕获触发器UFF1的D引脚。时钟的同一边沿需要Tcapture时间才能到达捕获触发器的时钟引脚,目的是使捕获触发器在下一个时钟周期捕获来自发起触发器的数据。如果在同一时钟周期内捕获数据,则捕获触发器中的预期数据(来自上一个时钟周期)将被覆盖,因此保持时间检查旨在确保捕获触发器中的目标数据不会被覆盖。保持时间检查可验证这两个时间之差(捕获触发器的数据到达时间和时钟到达时间)必须大于捕获触发器的保持时间,这样触发器上的数据才不会被覆盖,并且捕获到可靠的数据。

保持时间检查可以用数学公式表示为:

其中Tlaunch是发起触发器的时钟树延迟,Tdp是组合逻辑数据路径中的延迟,Tcapture是捕获触发器的时钟树延迟。换句话说,由时钟边沿发起的数据到达捕获触发器D引脚所需的总时间必须大于时钟同一边沿到达捕获触发器所需的时间加上保持时间。这样可以确保UFF1 / D保持稳定状态,直到触发器的时钟引脚UFF1 / CK时钟上升沿之后的保持时间为止。

保持时间检查对捕获触发器的数据路径施加了最小值(-min)约束,需要确定到捕获触发器D引脚的最快路径。这意味着将始终使用最短时序路径来进行保持时间检查,同样,通常在 fast timing corner下进行保持时间检查。

即使设计中只有一个时钟,时钟树也会导致时钟在发起触发器和捕获触发器处的到达时间大不相同。为了确保可靠的数据捕获,捕获触发器的时钟沿必须在数据可改变之前到达。保持时间检查可确保(见图8-11):

  • 当前数据发起时钟沿(Setup launch edge)的下一个时钟沿发起的数据不被当前数据捕获时钟沿(Setup receiving edge)所捕获。
  • 当前数据发起时钟沿发起的数据不被当前数据捕获时钟沿的前一个时钟沿所捕获。

如果发起时钟和捕获时钟都属于同一时钟域,则这两个保持时间检查实质上是相同的。但是,当发起时钟和捕获时钟处于不同频率或处于不同时钟域时,以上两个保持时间检查就有可能是不同的。在这种情况下,最差的保持时间检查就是所要报告的检查。上图8-11说明了这两个保持时间检查。

UFF0是发起触发器,UFF1是捕获触发器。建立时间检查在这一个数据发起时钟沿(Setup launch edge)和这一个数据捕获时钟沿(Setup receiving edge)之间。下一个数据发起时钟沿(Subsequent launch edge)不得以太快的速度传播数据,因为这可能会导致这一个数据捕获时钟沿没有时间可靠地捕获这一个数据。此外,这一个数据发起时钟沿同样不得以太快的速度传播数据,因为这可能会导致前一个数据捕获时钟沿(Preceding receiving edge)没有时间可靠地捕获前一个数据。在上述各种情况中,最差情况的保持时间检查对应于最严格的保持时间检查。

稍后将在8.3节和8.8节中分别讨论更通用的时钟,例如用于多周期路径和多频率路径的时钟。讨论内容将涵盖建立时间检查和保持时间检查之间的关系,尤其是如何从建立时间检查中推断出保持时间检查。虽然建立时间违例会导致设计的工作频率降低,但保持时间违例会“杀死”(kill)设计,即设计在任何频率下都无法运行。因此,了解保持时间检查并解决任何违例行为非常重要。

8.2.1 触发器到触发器路径(Flip-flop to Flip-flop Path)

本节基于图 8-2 中描述的示例说明了触发器到触发器的保持路径。以下是第 8.1 节中设置检查路径示例的保持时序检查的路径报告。

注意,路径类型(Path Type)为最小值(min),表示使用了最短路径的单元延迟值,这对应于保持时间检查。库保持时间(library hold time)指定了触发器UFF1的保持时间。如前3.4节所述,触发器的保持时间也可以为负。请注意,发起和捕获路径都是从时钟CLKM的上升沿(触发器的有效沿)开始计算的。时序报告显示,新数据最早可以到达UFF1、同时又可以安全地捕获上一个时钟周期数据的时间为0.19ns。由于新数据的实际到达时间为0.33ns,因此报告显示正的保持时间裕量(slack)为0.14ns。

图8-12显示了时钟信号到达发起和捕获触发器时钟引脚的时间,以及数据在捕获触发器处的最早允许到达时间和实际到达时间。由于数据实际到达的时间晚于数据所需到达的时间(允许的最早到达时间),因此满足保持时间要求。

保持时间裕量计算(Hold Slack Calculation)

需要注意的一点是,为建立时间和保持时间的时序报告计算裕量值的方式有所不同。在建立时间报告中,会计算数据实际到达时间和数据需要到达时间,然后将需要到达时间减去实际到达时间,从而得到建立时间的裕量值。但是,在保持时间报告中,当我们把需要到达时间减去实际到达时间后,负的结果将转化为正的裕量值(表示满足保持时间要求),而正的结果将转化为负的裕量值(表示保持时间违例)。

8.2.2 触发器路径的输入(Input to Flip-flop Path)

接下来描述来自输入端口的保持时序检查。有关示例,请参见图 8-4。输入端口上的最小延迟使用虚拟时钟指定为:

set_input_delay -clock VIRTUAL_CLKM \-min 1.1 [get_ports INA]

这是保持时间报告。

         input external delay中的值为输入延迟约束命令中的指定值。在0时刻的VIRTUAL_CLKM上升沿和CLKM上升沿之间进行保持时间检查。UFF2在不违反其保持时间的情况下捕获数据所需的到达时间为0.25ns,这表明数据应在0.25ns之后到达。由于数据实际上在1.2ns才到达,因此显示出0.95ns的正裕量。

8.2.3 触发器到输出路径(Flip-flop to Output Path)

这是一个输出端口的保持时序检查。有关示例,请参见图 8-6。输出端口命令显示为:

set_output_delay -clock VIRTUAL_CLKP \-min 2.5 [get_ports ROUT]

输出延迟是相对于虚拟时钟指定的。这是保持时间报告。

请注意,output external delay中的值为输出延迟约束命令中的指定值。

触发器到具有实际时钟的输出路径(Flip-flop to Output Path with Actual Clock)

有一条输出端口保持时间检查的路径,如图8-13所示。请注意,最小输出延迟是相对于实际时钟指定的。

set_output_delay -clock CLKP -min 3.5 [get_ports QOUT]
set_load 0.55 [get_ports QOUT]

8.2.4 输入到输出路径(Input to Output Path)

这是对输入到输出路径的保持时间检查,如图8-7所示。端口的约束为:

set_load -pin_load 0.15 [get_ports POUT]
set_output_delay -clock VIRTUAL_CLKM \-min 3.2 [get_ports POUT]
set_input_delay -clock VIRTUAL_CLKM \-min 1.8 [get_ports INB]
set_input_transition 0.8 [get_ports INB]

输入端口和输出端口上的延迟约束是相对于虚拟时钟指定的,因此,保持时间检查是在该虚拟时钟的上升沿(默认有效沿default active)处执行的。

8.3 多周期路径(Multicycle Paths)

在某些情况下,两个触发器之间的数据路径可能需要一个以上的时钟周期才能传播通过逻辑。在这种情况下,这条组合逻辑路径会被定义为多周期路径(multicycle path)。虽然数据还是会在每个时钟沿上都被捕获触发器捕获,但我们需要告知STA在指定数量的时钟周期之后才会出现有效的捕获时钟沿。

图8-14是一个示例。由于数据路径最多需要三个时钟周期,因此应指定三个周期的多周期建立时间检查。为此需要指定如下的多周期建立时间约束:

create_clock -name CLKM -period 10 [get_ports CLKM]
set_multicycle_path 3 -setup \-from [get_pins UFF0/Q] \-to [get_pins UFF1/D]

多周期建立时间约束规定,建立时间检查时从UFF0 / CK到UFF1 / D的路径最多可以花费三个时钟周期,这意味着设计每三个周期才会使用一次UFF1 / Q引脚上输出的数据,而不是每个周期都使用。

以下是一份具有多周期约束的建立时间路径报告:

注意,现在捕获触发器的时钟沿距离发起触发器的时钟沿三个时钟周期,为30ns。

现在,我们来检查一下多周期路径上的保持时间检查。在最常见的情况下,我们希望保持时间检查保持不变(与单周期路径一致),如图8-14所示,这样可使数据在三个时钟周期之内任意进行改变。只有指定多周期保持时间为2,才可以获得与单周期建立时间检查情况相同的保持时间检查。这是因为在没有这样的多周期保持时间约束的情况下,默认的保持时间检查是在建立时间捕获沿的前一个有效时钟沿上执行的,这显然不是我们希望的。我们需要将执行保持时间检查的时钟沿移动到默认时钟沿之前的两个周期,因此指定了多周期保持时间为2。预期的检查如图8-15所示,通过多周期保持时间约束,数据路径的最小延迟可以小于一个时钟周期。

set_multicycle_path 2 -hold -from [get_pins UFF0/Q] \-to [get_pins UFF1/D]

多周期保持时间约束命令中的周期数指定了从默认保持时间检查沿(建立时间捕获沿之前的一个有效沿)需要移回多少个时钟周期。 以下是一份保持时间检查的路径报告:

由于此路径的多周期建立时间约束为3,因此其默认保持时间检查是在建立时间捕获沿之前的有效时钟沿上执行的。在大多数设计中,如果最大路径(或建立时间)需要N个时钟周期,则大于(N-1)个时钟周期的最小路径约束是不可行的。通过指定两个周期的多周期保持时间约束,可以将保持时间检查时钟沿移回到数据发起沿处(即0ns处),如上面的路径报告中所示。

因此在大多数设计中,指定为N(周期)的多周期建立时间约束应伴随着指定为N-1(周期)的多周期保持时间约束。

如果指定了N个周期的多周期建立时间约束,但缺少了相应的N-1个周期的多周期保持时间约束,会发生什么情况呢?在这种情况下,会在建立时间捕获沿之前的一个周期时钟沿上执行保持时间检查。图8-16显示了仅约束多周期建立时间为3个周期时,进行这种保持时间检查的情况。

如图所示,这规定了数据只能在建立时间捕获沿之前的一个周期内进行改变。因此,数据路径必须具有至少两个时钟周期的最小延迟才能满足此要求。以下是这种情况的路径报告:

跨时钟域(Crossing Clock Domains)

让我们考虑在周期相同的两个不同时钟之间存在多周期路径的情况。(时钟周期也不同的情况将在本章后面进行介绍)

例子1:

create_clock -name CLKM \-period 10 -waveform {0 5} [get_ports CLKM]
create_clock -name CLKP \-period 10 -waveform {0 5} [get_ports CLKP]

多周期建立时间约束指定了给定路径的时钟周期数,如图8-17所示。默认建立时间捕获沿总是与发起沿相隔一个时钟周期,约束多周期建立时间为2会使建立时间捕获沿与发起沿相隔2个时钟周期。

多周期保持时间约束指定了保持时间检查应该在建立时间捕获沿之前几个时钟周期的时钟沿处执行,无论建立时间发起沿在何处,如图8-18所示。默认的保持时间检查是在建立时间捕获沿之前一个周期的时钟沿处执行的。约束多周期保持时间为1会将保持时间检查放置于默认保持时间检查之前一个周期的时钟沿处,因此变为建立时间捕获沿之前两个周期的时钟沿处。

set_multicycle_path 2 \-from [get_pins UFF0/CK] -to [get_pins UFF3/D]
# Since no -hold option is specified, the default option
# -setup is assumed. This implies that the setup
# multiplier is 2 and the hold multiplier is 0.

这是与多周期约束相对应的建立时间路径报告。

请注意,路径报告中指定的路径组始终是捕获触发器的路径组,在本例中为 CLKP。

接下来是保持时间检查的路径报告。由于多周期保持时间约束默认为0,因此将在建立时间捕获沿(20ns)之前一个时钟周期的10ns处进行保持时间检查。

以上报告报出了保持时间违例,这可以通过将多周期保持时间约束指定为1来消除。接下来将在一个单独的示例中说明这一点。

例子2:

下面给出了跨两个不同时钟域指定的多周期的另一个示例。

set_multicycle_path 2 \-from [get_pins UFF0/CK] -to [get_pins UFF3/D] -setup
set_multicycle_path 1 \-from [get_pins UFF0/CK] -to [get_pins UFF3/D] -hold
# The -setup and -hold options are explicitly specified.

以下是多周期建立时间约束为2时建立时间检查的路径报告:

以下是多周期保持时间约束为1时保持时间检查的路径报告:

请注意,本节中建立和保持检查的示例报告针对相同的时序角(timing corner)。然而,在最坏情况下的慢角(worst-case slow corner)通常最难满足建立时间检查(具有最低的裕量),而在最佳情况下的快速角( best-case fast corner)通常最难满足保持检查(具有最低的裕量)。

8.4 伪路径(False Paths)

当设计的功能运行时,某些时序路径可能不真实(或不可能)存在。在执行STA时可以将这些路径设置为伪路径(false path),这样就可以关闭这些路径,那么STA就不会对这些伪路径去进行分析了。

伪路径可能是从一个时钟域到另一个时钟域、从触发器的时钟引脚到另一触发器的输入引脚、通过一个单元的引脚、通过多个单元的引脚或这些情况的组合 。当通过单元的引脚指定了伪路径后,通过该引脚的所有路径都将被忽略,无需进行时序分析。辨别出伪路径的好处在于减少了分析空间,从而使分析可以专注于真实存在的路径,这同样有助于减少分析时间。但是,过多使用-through选项去指定伪路径同样会降低分析的速度。

可以使用set_false_path命令来约束伪路径,以下是一些例子:

set_false_path -from [get_clocks SCAN_CLK] \-to [get_clocks CORE_CLK]
# Any path starting from the SCAN_CLK domain to the
# CORE_CLK domain is a false path.set_false_path -through [get_pins UMUX0/S]
# Any path going through this pin is false.set_false_path \-through [get_pins SAD_CORE/RSTN]]
# The false path specifications can also be specified to,
# through, or from a module pin instance.set_false_path -to [get_ports TEST_REG*]
# All paths that end in port named TEST_REG* are false paths.set_false_path -through UINV/Z -through UAND0/Z
# Any path that goes through both of these pins
# in this order is false.

下面给出了一些关于设置伪路径的建议。要在两个时钟域之间设置伪路径,请使用:

set_false_path -from [get_clocks clockA] \-to [get_clocks clockB]

而不是

set_false_path -from [get_pins {regA_*}/CP] \-to [get_pins {regB_*}/D]

后者这种方式要慢得多。

另一个建议是尽可能少使用-through选项,因为它增加了运行时不必要的复杂性。仅在绝对有必要且没有替代方法可以指定该伪路径的情况下,才可以使用-through选项。

从优化的角度来看,还有一个建议是不要将一条多周期路径约束为伪路径。如果需要在已知或可预测的时刻对信号进行采样,则无论时间间隔多大,都应使用多周期路径约束,以使路径具有一定的约束条件并进行优化以满足多周期约束。如果把一条许多时钟周期后进行采样的路径指定为了伪路径,则对设计中其余逻辑路径的优化可能会使该路径变长,甚至超出所需的时间。

8.5 半周期路径(Half-Cycle Paths)

如果设计中同时具有负边沿触发的触发器(有效时钟沿为下降沿)和正边沿触发的触发器(有效时钟沿为上升沿),则设计中可能存在半周期路径(half-cycle path)。半周期路径可能是从一个触发器的上升沿到另一个触发器的下降沿,或者反过来。图8-19给出了一个示例,其中数据的发起沿在触发器UFF5的时钟下降沿,而数据的捕获沿在触发器UFF3的时钟上升沿。

以下是建立时间检查的路径报告:

请注意起点(Startpoint)和终点(Endpoint)中的边沿说明。时钟CLKP的下降沿出现在6ns,上升沿出现在12ns。因此,数据需要在半个周期6ns内到达捕获触发器的输入引脚。

虽然在建立时间检查时数据路径仅有半个时钟周期,但额外的半个周期可用于保持时间检查。以下是保持时间检查的路径报告:

保持时间检查通常是在捕获沿之前一个周期的捕获沿上执行的。由于捕获沿是在12ns处,因此前一个捕获沿在0ns处,故将在0ns处检查保持时间。这为保持时间检查有效地增加了半个时钟周期的裕量,因此可以看见保持时间检查有较大的正裕量(slack)。

8.6 移除时间检查(Removal Timing Check)

        移除时间检查( removal timing check)可确保在有效时钟沿与释放异步控制信号之间有足够的时间。该检查可确保有效时钟沿不带来影响,因为异步控制信号将保持有效状态,直到有效时钟沿之后一段撤销时间为止。换句话说,异步控制信号会在有效时钟沿之后被释放(变为无效),因此该时钟沿不会产生任何影响,如图8-20所示。该检查基于的是触发器异步引脚上指定的撤销时间。以下是单元库中与撤销时间检查有关的描述片段:

pin(CDN) {. . .timing() {related_pin : "CK";timing_type : removal_rising;. . .}
}

与保持时间检查一样,该检查也是针对最小路径的,不过是在触发器的异步引脚上。

终点(Endpoint)表明这是移除时间检查,且在触发器UFF6的异步引脚CDN上。该触发器的移除时间在报告中显示为library removal time,值为0.19ns。

所有异步时序检查均被分配给了async_default路径组。

8.7 恢复时间检查(Recovery Timing Check)

恢复时间检查(recovery timing check)可确保异步信号变为无效状态的时刻与下一个有效时钟沿之间的时间间隔大于一个最小值。换句话说,此检查可确保在异步信号变为无效状态之后,有足够的时间恢复,以便下一个有效时钟沿可以生效。例如,考虑从异步复位变为无效的时刻到触发器有效时钟沿之间的时间间隔。如果该时间间隔太短即有效时钟沿在复位释放后太早出现,则触发器可能进入未知的状态。恢复时间检查如图8-21所示。该检查基于的是触发器异步引脚上指定的恢复时间,单元库文件中与恢复时间有关的描述片段如下:

pin(RSN) {. . .timing() {related_pin : "CK";timing_type : recovery_rising;. . .}
}

与建立时间检查一样,该检查也是针对最大路径的,不过是在触发器的异步引脚上。

以下是一份恢复时间检查的路径报告:

终点(Endpoint)表明这是恢复时间检查,并且触发器UFF6的恢复时间在报告中显示为library recovery time,值为0.09ns。恢复时间检查也属于async_default路径组。

8.8 跨时钟域的时序(Timing across Clock Domains)

8.8.1 慢到快时钟域(Slow to Fast Clock Domains)

让我们来对一条从慢速时钟域到快速时钟域的路径来进行建立时间与保持时间检查,如图8-22所示。

这是以上示例的时钟定义:

create_clock -name CLKM \-period 20 -waveform {0 10} [get_ports CLKM]
create_clock -name CLKP \-period 5 -waveform {0 2.5} [get_ports CLKP]    

当发射触发器和捕获触发器的时钟频率不同时,STA通过首先确定一个共同的基周期来执行。下面给出了一个使用上述两个时钟进行STA时产生的消息示例。将较快的时钟展开,以获得一个普通周期。

Expanding clock 'CLKP' to base period of 20.00
(old period was 5.00, added 6 edges).

图8-23中为建立时间检查。默认情况下,将使用最严格的建立时间边沿去检查,在本例中为5ns处的时钟沿。以下是此时建立时间检查的路径报告:

请注意,发起时钟沿为0ns,而捕获时钟沿为5ns。

如前所述,保持时间检查与建立时间检查有关,并确保由当前时钟沿发起的数据不会干扰先前数据的捕获。这是保持时间检查的报告:

在上面的示例中,我们可以看到发起的数据在捕获时钟的第四个周期可用。让我们假设该设计的目的不是在CLKP的下一个有效沿上就捕获数据,而是在每第4个捕获沿上捕获数据。该假设给触发器之间的组合逻辑路径提供了4个CLKP周期的时间,即20ns。我们可以通过设置以下多周期路径约束来做到这一点:

set_multicycle_path 4 -setup \-from [get_clocks CLKM] -to [get_clocks CLKP] -end

-end选项指定了多周期4是用于终点(endpoint)或捕获时钟的。此多周期路径约束将建立时间和保持时间检查更改为了图8-24中所示。

以下是这种情况下建立时间检查的路径报告:

上图8-24中也说明了保持时间检查,请注意,保持时间检查是根据建立时间检查而决定的,默认为当前数据捕获沿之前的一个周期。以下是保持时间检查的路径报告。注意,保持时间捕获沿为15ns,比建立时间捕获沿(20ns)早一个周期(5ns)。

在大多数设计中,这不是理想的时序检查,应将保持时间检查一直移回到数据发起沿所在位置。因此,我们可以约束多周期保持时间为3。

set_multicycle_path 3 -hold \-from [get_clocks CLKM] -to [get_clocks CLKP] -end

3是指将保持时间检查沿向后移三个CLKP时钟周期,即0ns时刻处。与多周期建立时间约束的区别在于:在多周期建立时间约束中,建立时间捕获沿会从默认的建立时间捕获沿向前移动指定的周期数;而在多周期保持时间约束中,保持时间检查沿会从默认的保持时间检查沿向后移动指定的周期数。-end选项意味着我们想将终点(或捕获边沿)移回指定的周期数,即捕获时钟的周期数。代替-end的另一种选项-start指定了要移动的发起时钟周期数,-end选项指定了要移动的捕获时钟周期数。-end是多周期建立时间约束的默认值,-start是多周期保持时间约束的默认值。

使用多周期保持时间约束,可以将保持时间检查的时钟沿往回移,检查效果如图8-25所示。具有多周期保持时间约束的保持时间检查路径报告如下: ​​​​​​

         总之,如果指定了N个周期的多周期建立时间,那么很可能还应指定N-1个周期的多周期保持时间。对于慢速到快速时钟域之间的路径,多周期路径约束的一个好经验是使用-end选项。使用此选项,可以根据快速时钟的时钟周期来调整建立时间和保持时间检查。

8.8.2 快到慢时钟域(Fast to Slow Clock Domains)

在本小节中,我们考虑数据路径从快速时钟域到慢速时钟域的示例。使用以下时钟定义时,默认的建立时间和保持时间检查如图8-26所示。

create_clock -name CLKM \-period 20 -waveform {0 10} [get_ports CLKM]
create_clock -name CLKP \-period 5 -waveform {0 2.5} [get_ports CLKP]

总共可能有四种建立时间检查,请参阅图8-26中的Setup1,Setup2,Setup3和Setup4。其中,最严格的是Setup4检查。以下是此最严格检查的路径报告。请注意,数据发起时钟沿为15ns,捕获时钟沿为20ns。

与建立时间检查类似,总共也可能有四种保持时间检查。图8-26中所示为最严格的保持时间检查,该检查可确保0ns处的捕获沿不捕获0ns处正在发起的数据。以下是这种情况下保持时间检查的路径报告。

通常,设计人员可以将从快时钟域到慢时钟域的数据路径指定为多周期路径。如果想要放宽建立时间检查,比如为数据路径提供两个快时钟周期,则此多周期路径约束如下:

set_multicycle_path 2 -setup \-from [get_clocks CLKP] -to [get_clocks CLKM] -start
set_multicycle_path 1 -hold \-from [get_clocks CLKP] -to [get_clocks CLKM] -start
# The -start option refers to the launch clock and is
# the default for a multicycle hold.

在这种情况下,图8-27中为用于建立时间和保持时间检查的时钟沿。-start选项指定周期数的单位(在这种情况下为2)是发起时钟周期(在这种情况下为CLKP)。约束多周期建立时间为2会将发起沿移动到默认发起沿之前的一个时钟沿,即在10ns而不是默认的15ns处。多周期保持时间约束确保了在0ns处发起沿发起的数据,不会被0ns处的捕获沿捕获到。

以下是建立时间检查的路径报告。与预期一样,发起时钟沿为10ns,捕获时钟沿为20ns。

以下是保持时间检查的路径报告。保持时间检查是在0ns处执行的,此时捕获时钟和发起时钟均为上升沿。

与从慢速时钟域到快速时钟域的路径不同,在从快速时钟域到慢速时钟域的路径中,多周期路径约束的一个好经验是使用-start选项,然后再根据快速时钟调整建立时间和保持时间检查。

8.9 例子

在本节中,我们将介绍发起和捕获时钟的不同情况,并分别说明如何执行建立时间和保持时间检查。图8-28为所举例子的示意图:

半周期路径 - 案例 1(Half-cycle Path - Case 1)

在此示例中,两个时钟具有相同的周期,但相位相反。以下是时钟定义,其波形如图8-29所示。

create_clock -name CLKM \-period 20 -waveform {0 10} [get_ports CLKM]
create_clock -name CLKP \-period 20 -waveform {10 20} [get_ports CLKP]

建立时间检查是从发起沿(0ns)到下一个捕获沿(10ns)的。半个时钟周期的裕量可用于保持时间检查,以验证在20ns处发起的数据是否在10ns处未被捕获沿所捕获。以下是建立时间检查的路径报告。

以下是保持时间检查的路径报告。

半周期路径 - 案例2(Half-cycle Path - Case 2)

此示例与情况1类似,不过发起时钟和捕获时钟的相位相反。以下是时钟定义,其波形如图8-30所示。

create_clock -name CLKM \-period 10 -waveform {5 10} [get_ports CLKM]
create_clock -name CLKP \-period 10 -waveform {0 5} [get_ports CLKP]

建立时间检查从5ns的发起时钟沿到10ns的下一个捕获时钟沿。保持时间检查从5ns的发起时钟沿到0ns的捕获时钟沿。以下是建立时间检查的路径报告。

以下是保持时间检查的路径报告。

快到慢时钟域(Fast to Slow Clock Domain)

在此示例中,捕获时钟是发起时钟的二分频。以下是时钟定义。

create_clock -name CLKM \-period 10 -waveform {0 5} [get_ports CLKM]
create_clock -name CLKP \-period 20 -waveform {0 10} [get_ports CLKP]

波形如图8-31所示。建立时间检查是从10ns的发起沿到20ns的捕获沿,保持时间检查是从0ns的发起沿到0ns的捕获沿。

以下是建立时间检查的路径报告:

以下是保持时间检查的路径报告:

慢到快时钟域(Slow to Fast Clock Domain)

在此示例中,捕获时钟速度是发起时钟速度的2倍。图8-32中为建立时间和保持时间检查对应的时钟沿:从发起沿0ns到下一个捕获沿5ns进行建立时间检查,保持时间检查是在建立时间捕获沿前一个周期的捕获沿进行的,也就是说,发起沿和捕获沿都为0ns。

以下是建立时间检查的路径报告。

以下是保持时间检查的路径报告

8.10 多倍时钟(Multiple Clocks)

8.10.1 整数倍数(Integer Multiples)

在设计中通常会定义多个时钟,这些时钟的频率是彼此的整数倍。在这种情况下,会通过计算所有相关时钟(related clocks)之间的公共基本周期来执行STA(如果两个时钟域之间具有数据路径,则两个时钟相关)。建立公共基本周期的目的是以便所有时钟都同步。

以下是3个相关时钟的示例:

create_clock -name CLKM \-period 20 -waveform {0 10} [get_ports CLKM]
create_clock -name CLKQ -period 10 -waveform {0 5}
create_clock -name CLKP \-period 5 -waveform {0 2.5} [get_ports CLKP]
Expanding clock 'CLKP' to base period of 20.00 (old period was
5.00, added 6 edges).
Expanding clock 'CLKQ' to base period of 20.00 (old period was
10.00, added 2 edges).

分析CLKP和CLKM时钟域之间的路径时,将使用20ns的公共基本周期,如图8-33所示。

以下是建立时间检查的路径报告,用于从较快时钟CLKP到较慢时钟CLKM的路径。

相应保持时间检查的路径报告如下:

8.10.2 非整数倍数(Non-Integer Multiples)

考虑当两个频率不是彼此整数倍的时钟域之间存在数据路径的的情况。例如,发起时钟是公共时钟的8分频,而捕获时钟是公共时钟的5分频,如图8-34所示。本节将介绍在这种情况下如何执行建立时间和保持时间检查。

以下是时钟定义,其波形如图8-35所示:

create_clock -name CLKM \-period 8 -waveform {0 4} [get_ports CLKM]
create_clock -name CLKQ -period 10 -waveform {0 5}
create_clock -name CLKP \-period 5 -waveform {0 2.5} [get_ports CLKP]

时序分析会先计算相关时钟的公共周期,然后再将时钟扩展到该公共周期。请注意,仅针对相关时钟(即在它们之间具有时序路径的时钟)去计算公共周期。CLKQ和CLKP之间数据路径的公共周期仅扩展为10ns的公共周期,CLKM和CLKQ之间数据路径的公共周期为40ns,而CLKM和CLKP之间数据路径的公共周期也为40ns。

让我们考虑一条从CLKM时钟域到CLKP时钟域的数据路径,这种情况下时序分析的公共基本周期为40ns。

Expanding clock 'CLKM' to base period of 40.00 (old period was
8.00, added 8 edges).
Expanding clock 'CLKP' to base period of 40.00 (old period was
5.00, added 14 edges).

建立时间检查在时钟发起沿和捕获沿之间的最短时间内进行。在我们从CLKM到CLKP的示例路径中,这就是24ns处的时钟CLKM发起沿以及25ns处的时钟CLKP捕获沿。

以下是保持时间检查的路径报告,最严格的保持时间检查是从0ns处的CLKM发起沿到0ns处的CLKP捕获沿。

现在,我们对从CLKP时钟域到CLKM时钟域的路径的建立时间进行检查。在这种情况下,最严格的建立时间检查是从15ns处的时钟CLKP发起沿到16ns处的时钟CLKM捕获沿。

以下是保持时间检查的路径报告,同样,最严格的还是0ns处的检查。

8.10.3 相移(Phase Shifted)

在以下示例中,两个时钟有90°的相移(phase shift):

create_clock -period 2.0 -waveform {0 1.0} [get_ports CKM]
create_clock -period 2.0 -waveform {0.5 1.5} [get_ports CKM90]

图8-36给出了使用这两个时钟的示例。

建立时间检查的路径报告如下:

0.5ns处的CKM90第一个上升沿是捕获沿,保持时间检查是在建立时间捕获沿之前一个周期的时钟沿处。对于2ns的发起沿,建立时间捕获沿为2.5ns,因此保持时间检查沿就在0.5ns处的前一个捕获沿。保持时间检查的路径报告如下:

在第10章中还会介绍其它时序检查,例如数据到数据(data to data)检查和时钟门控(clock gating)检查。

《静态时序分析实用方法》第八章翻译相关推荐

  1. 《静态时序分析实用方法》翻译

    第1章 引言 解释了什么是静态时序分析以及它如何用于时序验证.还描述了功率和可靠性方面的考虑. 概述了纳米设计的静态时序分析程序.本章解决了诸如什么是静态时序分析.噪声和串扰的影响是什么.如何使用这些 ...

  2. 《静态时序分析实用方法》第七章翻译

    第 7 章 配置 STA 环境(Configuring the STA Environment) 第 7 章是后续章节的先决条件.它描述了如何配置时序分析环境.第 7 章描述了指定时钟.IO 特性.伪 ...

  3. 《静态时序分析实用方法》 第一章翻译

    第1章 引言 解释了什么是静态时序分析以及它如何用于时序验证.还描述了功率和可靠性方面的考虑. 概述了纳米设计的静态时序分析程序.本章解决了诸如什么是静态时序分析.噪声和串扰的影响是什么.如何使用这些 ...

  4. 《静态时序分析实用方法》第六章翻译

    第 6 章 串扰和噪声(Crosstalk and Noise) 在纳米技术中,串扰的影响在设计的信号完整性中起着重要作用.本章描述相关的噪声和串扰分析,即毛刺分析和串扰分析.这些技术使 ASIC 从 ...

  5. 翻译不是一个有效的路径_【第一章:绪论】静态时序分析圣经翻译计划

    本文由知乎赵俊军授权转载,知乎主页为https://www.zhihu.com/people/zhao-jun-jun-19 众所周知,静态时序分析是IC工程师必备知识点,也是秋招中笔试面试的高频考点 ...

  6. delay 芯片时序output_【第二章 STA概念 上】静态时序分析圣经翻译计划

    本文由知乎赵俊军授权转载,知乎主页为https://www.zhihu.com/people/zhao-jun-jun-19 本章节介绍CMOS技术的基础知识以及执行静态时序分析所涉及的术语. 2.1 ...

  7. 以下不属于时序逻辑电路的有_静态时序分析圣经翻译计划——附录B:SDF

    本附录将介绍标准延迟标注格式,并说明了如何在仿真中执行反标. 延迟格式描述了设计网表的单元延迟和互连走线延迟,无论设计是用两种主要硬件描述语言(VHDL或Verilog HDL)中的哪一种所描述的. ...

  8. 中set无效是怎么回事_静态时序分析圣经翻译计划——第十章:鲁棒性检查 (中)...

    10.5 时钟门控检查 当一个门控信号(gating signal)可以控制逻辑单元中时钟信号(clock signal)的路径时,将会执行时钟门控检查(clock gating check),一个示 ...

  9. 静态时序分析-时序违例解决方法

    文章目录 时序优化 1.优化建立时间和时序设计规则 1.1 改变单元位置 1.2 改变单元的大小 1.3 插入缓冲单元 1.4删除缓冲单元 1.5 重分配负载 1.6 时钟有用偏斜 2.优化保持时间 ...

最新文章

  1. linux逻辑盘大小,linux – 物理和逻辑盘区大小
  2. 101PPT游戏化换肤遇到的问题
  3. [android] Serializable 和 Parcelable 区别
  4. 信息学奥赛一本通 1124:矩阵加法 | OpenJudge NOI 1.8 08:矩阵加法
  5. ECMAscript6(ES6)新特性语法总结(一)
  6. mysql5.6.27安装_mysql-5.6.27源码安装及错误解决办法
  7. Android Studio系列教程四--Gradle基础
  8. Spring Boot整合模板引擎freemarker
  9. 北京交通大学第六届新生程序设计竞赛题解
  10. 静音抑制_正在研究利润以抑制创新
  11. H3CSE园区-组播路由协议
  12. maxscale mysql5.7_Centos7安装maxscale 实现mysql的读写分离
  13. 【技术贴】解决打开程序出错,提示错误429,activex部件不能创建对象,不用重装系统。...
  14. SIM7600CE-CNSE 4G模块 树莓派/Windows连网指南
  15. 国家药品监督管理局药品审评中心—重点功能介绍
  16. (转)给想立志入行网络或已经初入行的朋友的建议
  17. 如何通过网易云的分享链接,找到相关人的网易云账号
  18. java实现生成二维码
  19. MySQL基础篇3——DDL、DML、DCL使用篇
  20. 计算机硬盘无法启动怎么办,电脑开机找不到硬盘怎么办?

热门文章

  1. 美网络安全公司称非蓝牙类无线鼠标和键盘存隐患
  2. 圣经学习网站 ////英文学习网站
  3. ESP32/ESP8266安装arduino开发板失败的方法(附合宙esp32用blinker固件连接小爱同学提示“要操作的设备好像出问题了等一会再试吧”的解决方法
  4. 了解JavaScript for ... of循环
  5. MyZip pro专业极速解压放弃了Mac上落后的拖拽解压压缩模式,采用『右键菜单』进行压缩、解压,极大的符合了用户最初的使用习惯。
  6. 【计算机毕业设计】汽车租赁平台
  7. TDK| 电源——反激变压器设计过程
  8. 51单片机开发 矩阵键盘中断实验与简易计算器及proteus仿真
  9. yoga tab3 linux,全面进化联想YOGATab3Pro平板评测
  10. 昆仑通态触摸屏与2台台达变频器及2台仪表通讯控制