本篇文章将给大家带来时序分析相关的东西。
课程大纲如下所示:
1、Sequential Clocking
对于绝大部分数字电路而言,其都采用同步电路的设计方法。这种设计方法基于寄存器为主体,描述数据在寄存器和寄存器之间的传输。因此描述其的语言也被称为RTL,即寄存器传输级。
我们假定所有的寄存器都是D-Flip Flops,时钟上升沿触发。其有以下几个关键的指标。
首先就是tcq。其描述了在时钟上升沿到达以后,数据多久才可以从D端到达Q端,为什么不叫tdq呢?因为CLK实际上才是数据的开关,其上升沿以后数据才开始从D端流动到Q端。
学过数字电路都知道,实际的电路不是理想的,不可能时钟上升沿一到来,出口数据就发生了变化。具体的时序如下图所示。
我们再来看一下什么是建立时间。大家可以简单的这么理解,对于寄存器而言,其有两个工作状态,一个是高电平,一个是低电平。在低电平的时候,其入口是开启的,一旦进入高电平,其会关闭自己的入口。
因此就需要你在入口开启之前将数据维持稳定。同样电路不是理想的,不可能说你一稳定,马上就把你的数据采样进寄存器了,其需要一个时间,这个时间我们就可以理解成建立时间,其时序图如下图所示。
同样的,当电平为高电平的时候,入口会关闭。其关闭也不是马上的,大家可以理解为开门关门,都是需要一个时间的。所以在关门的这段时间你的数据应该维持不变,如果你的数据变了,那可以采样到的数据就不是你希望的数据了。这个上升沿之后还需要维持数据的时间,就是所谓的保持时间了。
基于上述的分析我们可以发现。在时钟上升沿之前和上升沿之后,我们都需要数据维持在我们希望的那个数据上。这就引入了两个概念,Max Delay和Min Delay。
什么是Max Delay呢?根据上面的描述我们知道,电路需要在时钟上升沿的建立时间之前,将数据稳定下来。那又为什么会出现数据不稳定呢?那就是你在一个时钟周期内,结果还没算出来,或者是还没有传到寄存器的入口处,这样就出现了建立时间违例。
可以看到,建立时间违例和时钟周期是紧密相关的。这就好比,你需要每个时钟周期从一个门到另外一个门,这里的一个个的门就是寄存器。你如果没有在规定时间赶到,门就关上了,那自然也就出错了。
而什么是保持时间违例呢?那就是上面说的数据没有维持住,在时钟上升沿以后过了一下下就变了。为什么没有维持住?因为数据更新的太快了,这就好比你和另外一个人都需要从一个门到另外一个门。按理来说你始终比他领先一个门,但你赶在关门之前到了某一个门,他突然一下就到了你面前,这个时候你们谁过去呢?这就出现了数据亚稳态。
为什么会有上述的原因?可能是因为你后面那个人走了捷径,或者是跑的太快了。对应到数字电路就是其data path太短了。可以看到,建立时间违例跟时钟周期没有关系。
我们结合实际的电路去理解上述的概念。在时钟上升沿到来以后,经过的时间,数据呈现在寄存器的Q端,然后又需要经过组合逻辑,到达另外一个寄存器的D端。其本质上我们可以看作一个跑步竞赛。
数据必须在下一个时钟上升沿的建立时间之前,到达下一个寄存器的D端。我们将其称为发射和捕获。
我们再细化一下上面的概念,根据下面的电路图,很显然可以划分为两条路径。一个是Capture Path即捕获路径,一个是Launch Path即发射路径。下一个时钟上升沿到来之前,这个寄存器的输入端必须是已经稳定了的数据。大家可以类比上面的关门例子。
通常来说,如果发生建立时间违例,通常都是组合逻辑太长导致的,组合逻辑太长,导致数据没办法在下一个时钟上升沿之前到达R2寄存器的D端,数据走的太慢了!因此用了一只乌龟作为示例,根据下图我们也可以得出这个结论。
我们再来看一下保持时间带来的约束。我们也将其称为Min Delay。值得注意的是,此时两个寄存器看到的都是同一个时钟上升沿,出现保持时间违例的关键在于数据到的太快了,B寄存器还没有把门关上,你就到了,这不是希望看到的。我们可以结合下面的时序图和电路图来理解。
为什么会造成这个原因呢?基本上是因为布局布线没做的特别好,两个寄存器太近了,中间也没有什么组合逻辑。数据嗖的一下就到了另外一个寄存器。因为用了一个人跑步来做示例。Hold Violation其实很好解决。既然你走的太快了,那就中间插入一点不影响逻辑功能的逻辑,让你走慢一点,就好像插入一个缓冲带。或者就让下一级的时间到的早一点,可以理解为让门早点关上。(使用该方法要慎重,其相当于人为引入clock skew,什么是clock skew后面再解释)
综上分析,我们可以得到下面的公式,其本质就是描述数据到D的时间和时钟到CLK的时间的关系。
我们来做一个总结,其实简单来说。关键是看两个路径,一个是数据什么时候到寄存器D端,一个是时钟上升沿什么时候到寄存器的时钟端口。
2、Static Timing Analysis
接下来我们看一个非常重要的概念,静态时序分析即STA。
我们来给时序路径做一个定义。时序路径包括一个起始点,一个结束点。起始点有两种情况,一个是整个设计的输入端口,另外一个就是寄存器的Clock pin。而结束点的话为寄存器的输入pin(不包括clock pins),或者是整个设计的输出端口。因此一共就有2x2=4种情况。具体的我们往后接着看。
我们直接看下图,静态时序分析的路径被划分为四种。最最常见的是reg2reg。即从一个寄存器的CLK pin到另外一个寄存器的D(或者en) pin。
我们来看一下静态时序分析的目标。基于约束条件,检查max delay和min delay是否都符合规则。这里PPT讲的不太清楚,我们往下接着看几个实际的例子,就清楚了。
我们假设这个模块就是整个设计了。从原始输入到每个SP,我们认为消耗时间为0。从EP到输出,我们认为消耗时间也是0。
对于时序分析而言,我们采用基于节点的分析方式,我们不会把每一条路径都罗列出来。这样当节点增大的时候,会出现数据爆炸。相对的,我们基于节点分析,找到相对于该节点最差的路径。
由此引出了两个概念,一个是数据到达节点的时间,一个是数据应该需要什么时候到达节点。如果到达节点的时间晚于需要到达的时间,则会出现时序违例。(我们在这里只分析max delay,min delay暂时不谈)
我们将逐级的分析ATs和RATs。下面这个图还不是特别直观,我们直接看个例子。
假设我们已经有了下面的模型,时钟周期是12的话,下面这个电路是否满足要求呢?我们基于上面的概念进行分析。
首先,我们构建好图。下面的数字代表AT,即数据到达时间。从SRC到a,b,c时间为0,这个前面已经谈过。从a到d的时间为1,从d到g的时间为3,则g的AT为3+1=4。对于f,其可以从d过来,也可以从b过来。从d过来到达时间为5+1=6,从b过来时间为0+4=4,我们选最晚到达的时间,所以f的AT为6。
基于此,可以逐步得到到达SNK的AT为15。
对于RAT,我们要从右向左看,SNK的RAT为12,则j,k,h的RAT也都为12。对于h而言,如果要满足k的要求,则其RAT应该为10,如果要满足n的要求,则其RAT应该为12-5=7。我们取较小的值,则h的RAT为7。基于此规则,我们可以填上所有的RAT。
很显然,此时我们可以得到关键路径是哪一条,并且发现这个关键路径是违例的。
我们再来看一个概念,False Path。即虚假路径,为什么这么叫呢?因为这条路径实际上是不会经过的。比如下图,两个MUX一个用SEL,一个用~SEL。那么这样的话,其不可能做出同样的选择(比如左边图的都选择SEL=0的情况)。
左边那条路径实际上是肯定不会走的,这种路径就是False Path。但STA工具不知道这一点,因此我们需要自己手动设置。
3、Design Constraints
我们再来看一个非常重要的概念,设计约束。
上一篇文章已经提到了,综合工具是基于约束条件去做综合。而不是漫无目的的去做综合。这个约束条件需要我们自己提供,通常我们采用SDC语法。该语法是TCL语言的超集。
通过约束我们给芯片一个指定的工作环境。告诉芯片工作在什么频率啊,时钟信号怎么样啊,你面积应该有多大啊等等。然后综合工具就会往这个方向去努力综合,让芯片可以在这个约束条件工作起来。
这里提一个重要的概念,集合。SDC中的collection和TCL中的列表不一样。collection的元素本质上是一个个的指针,指向你想要的元素。想使用具体的元素,应该用下面的语法。这里其实就需要大家自己去看相应的视频教程和官方文档了。
我们来看一些设计目标的一些名称。在写设计约束的时候,这些名词会被反复调用,比如get_ports
等。对于一个模块,其顶层名称就是我们的design
。其对外引出的端口叫做port
。调用的模块称为reference
,例化的实例叫做cell
。具体的大家看一下下面的代码和对应的概念即可。
有了上述的概念,就可以做很多事了,比如下面的语法。这里举个例子,想要获取所有的叫做clk的端口,设置成为理想始终网络,便可以使用下面的语法。更加具体的用途大家可以找几个sdc看一看,有了这篇文章的说明,大家结合查资料。大概可以搞清楚到底是在约束什么。
set_ideal_network [get_ports clk]
我们再来看一下时钟定义,时钟定义可以说是综合最重要的东西了。涉及到时钟的信号一定要声明好,否则会被视为普通信号,从而不会进行相应的时序分析,后果很严重。
我们来看一下怎么创建时钟,如下图所示。
下面这个generated clock稍微复杂一点,我解释一下,其中create_generated_clock
是SDC中的一个命令,用于定义一个由设计中某个现有的时钟信号生成的派生时钟(derived clock)。这个命令通常用于以下几种情况:
当设计中存在时钟分频器时,需要为分频后的时钟定义派生时钟。
当时钟网络中存在时钟树时,需要为时钟树的分支定义派生时钟。
整个命令的意思是:创建一个名为gen_clock
的派生时钟,其源时钟是设计中的clk
端口,该派生时钟是源时钟的一半频率,并且这个派生时钟用于作用名为FF1
的触发器的输出引脚Q
。
有关时钟的定义还有以下一些语法,我这里分别解释一下。
set_ideal_network
命令是用来指定一个网络(通常是时钟或复位信号)应该被综合工具视为理想网络。这意味着这个网络被假设为没有延迟和抖动,并且具有无限的能力来驱动负载。在实际的硬件实现中,时钟网络总是会有一定的延迟和抖动,因此set_ideal_network
命令不适用于描述真实世界的时钟行为。随着设计流程的进展,会用更准确的时钟模型来替换这个理想模型,以便进行更精确的时序分析和优化。
set_clock_transition
命令用于指定时钟信号在逻辑电平之间转换的时间。这个转换时间通常被称为时钟的边沿斜率(edge slope),它表示时钟信号从低电平跳变到高电平或从高电平跳变到低电平时所需的时间。
set_clock_uncertainty
命令用于指定时钟信号的不确定性。时钟不确定性是由于时钟信号在传播过程中的各种因素(如时钟偏斜、时钟抖动、环境噪声等)导致的时钟边沿到达时间的不确定性。当考虑不确定性的时候,自然会让综合变得更加困难,如果考虑不确定性都能PASS,那在理想时钟下更加会PASS。
set_propagated_clock
命令用于指定一个时钟信号是一个已传播的时钟。已传播的时钟通常是指在设计中通过时钟网络传播后的时钟信号,它可能包含了时钟树综合(clock tree synthesis)后的延迟。
谈完了时钟的约束以后,我们再来看一下IO的约束。其实把时钟约束好以后,reg2reg
的路径都已经解决了,但我们还有三种路径没有解决,因此我们要定义好输入输出约束,简单来说就是要定义好输入延迟和输出延迟。
此外还有一种替代方式,如下所示。
上述概念的具体图示如下所示,这里简单解释一下。
首先是input delay
,该概念非常简单,之前我们认为输入进来的时候刚好对应时钟的上升沿,没有任何的延迟,但实际上肯定不现实,肯定是过了一会才来的。这个值如果设的很高的话,则意味着输入信号要很久才到来,那后面能做逻辑的时间就很短了。
然后是output delay
,这个稍微难理解一点。其描述了模块输出到下一级模块需要多少延迟,也可以理解为在捕获沿到来时,数据已经存在的时间。我们想一想,这个延迟如果设的很大,那么我们数据就应该提前很久已经算出来了,能做的逻辑又减少了。因此对于这两个delay,一般不要设的太大,否则布局布线会很困难,当然也不可能乱设置,具体还是取决于上级模块和下级模块。此外我们还要考虑min delay path
,这个大家可以自己思考。
除此之外输入驱动和输出负载,可以视为电阻或电容模型。
我们回顾一下false path,其语法设置如下所示。这里我详细解释一下。set_false_path
命令用于指定设计中某些路径不会影响时序分析的结果。这通常用于那些不依赖于时钟周期或不需要满足特定时序要求的路径,例如复位路径、异步信号路径或某些测试路径。
命令set_false_path through [get_pins mux1/I0] through [get_pins mux2/I0]
的含义如下:
set_false_path
:用于标记一些路径为“假路径”(false paths),即这些路径上的时序违例不会被报告为设计错误。through [get_pins mux1/I0]
:这指定了假路径的第一个点,即mux1
的输入引脚I0
。get_pins
是一个SDC函数,用于选择设计中的特定引脚。through [get_pins mux2/I0]
:这指定了假路径的第二个点,即mux2
的输入引脚I0
。
综合以上,这个命令告诉时序分析工具,从mux1
的输入引脚I0
到mux2
的输入引脚I0
的路径是一个假路径。这意味着在这两个引脚之间的任何时序违例都不会被视为设计错误,时序分析工具在分析时序时会忽略这条路径。
上面讲的是不会走的路径。此外还有跨时钟域的时钟约束。这里我重点解释一下最后那个。
set_multicycle_path
命令用于指定某些特定的时序路径可以超过一个时钟周期来完成数据的建立(setup)或保持(hold)。
命令set_multicycle_path setup from F1/CP to F2/D 2
的含义如下:
set_multicycle_path
:用于设置多周期路径约束。setup
:这指定了约束的类型是建立时间,即数据必须在时钟边沿到达之前在输入端稳定的时间。from F1/CP
:这指定了路径的起始点,即从触发器F1
的时钟引脚CP
开始。to F2/D
:这指定了路径的终点,即到触发器F2
的数据引脚D
结束。2
:这指定了允许的最大时钟周期数。在这个例子中,它表示从F1
到F2
的路径可以有最多两个时钟周期的延迟。
综合以上,这个命令告诉时序分析工具,从F1
的时钟引脚到F2
的数据引脚的路径是一个多周期路径,并且在建立时间分析中允许有最多两个时钟周期的延迟。这意味着F2
可以在F1
的时钟边沿之后的第二个时钟周期内采样到稳定的数据。
这种约束通常用于以下情况:
长路径:在某些情况下,由于路径过长,数据无法在一个时钟周期内到达目的地,因此需要多个时钟周期。
特殊逻辑:某些复杂的逻辑操作可能需要多个时钟周期来完成。
使用set_multicycle_path
命令可以帮助时序分析工具更准确地评估设计的时序性能,并确保在允许的时钟周期内数据能够稳定。
很多时候,设计中的某些值会是一个常数,用于表示特定的工作状态。一旦这样设置,很多路径就是false path了。比如0送到mux的sel端。为了解决这种情况,使用下面的方法。
set_case_analysis
命令用于指定一个信号或端口在综合或时序分析期间的固定逻辑值。这个命令通常用于模拟某些特定的设计状态,例如测试模式或配置模式,而不需要实际改变硬件的物理连接。
命令set_case_analysis 0 [get_ports TEST_MODE]
的含义如下:
set_case_analysis
:这是SDC命令,用于设置案例分析约束。0
:这指定了信号或端口的固定逻辑值。在这里,它表示TEST_MODE
端口被固定为逻辑0。[get_ports TEST_MODE]
:这是一个SDC函数,用于选择设计中的特定端口。在这里,它指定了TEST_MODE
端口。
综合以上,这个命令告诉综合或时序分析工具,在进行分析时,将TEST_MODE
端口视为固定为逻辑0。这意味着在分析过程中,工具会假设TEST_MODE
端口始终输出逻辑0,而不管实际电路中的信号如何变化。
这种约束通常用于以下情况:
测试模式:在设计验证期间,可能需要模拟某些测试条件,通过固定某些测试模式控制信号的值来简化测试过程。
安全性分析:在某些安全性关键的系统中,可能需要分析在特定配置下的系统行为,例如在故障安全模式下的操作。
配置设置:对于可配置的逻辑,可能需要分析不同的配置设置对性能的影响。
使用set_case_analysis
命令可以帮助设计者在不同的设计状态下进行分析,而不需要对硬件进行物理上的修改。这有助于提高设计的验证覆盖率和确保在各种操作模式下设计的稳定性。
此外还有DRV约束,比如最大扇出啥的,具体的大家看下图即可。
本节课后面还有如何看报告以及MMMC讲解。但讲的比较粗略,并且报告是cadence的报告,我也没接触过,这里就不写了,感兴趣的可以自己看一下。
下一篇文章将进入芯片后端。
系列文章入口——
【芯片验证】sva_assertion: 15道助力飞升的断言练习 |
【芯片验证】可能是RTL定向验证的巅峰之作 |
【芯片验证】RTL仿真中X态行为的传播 —— 从xprop说起 |
【芯片验证】年轻人的第一个systemVerilog验证环境全工程与解析 |
【芯片设计】verilog中有符号数和无符号数的本质探究 |
【芯片设计】论RTL中always语法的消失术 |
【芯片设计】代码即注释,注释即代码 |
【芯片设计】700行代码的risc处理器你确实不能要求太多了 |
入职芯片开发部门后,每天摸鱼之外的时间我们要做些什么呢 |
如何计算系统的outstanding 和 burst length? |
芯片搬砖日常·逼死强迫症的关键词不对齐事件 |
熟人社会里,一群没有社会价值的局外人 |