时序优化学习笔记

1.适当进行逻辑复制以优化设计速度(减少扇出)

逻辑复制是指当某个信号扇出比较大时,会造成该信号到各个目的逻辑节点的路径变得过长,从而成为设计中的关键路径,为了解决这个问题,可以通过在书写代码时对该信号进行复制,已达到分担该信号扇出过多的目的。

例如: assign a=b &c; 而在代码中多处用到a,可以改写为如下

    assign a1=b&c; 

     assign a2=b&c;

在代码中使用a1 a2来分担a,从而减小了a的扇出,缩短布线延时

 

2.通过减少关键路径上的组合逻辑级数来优化时序

FPGA逻辑设计中时序路径上的组合逻辑都会给路径增加延时,从而影响设计性能的往往只有几条关键的路径而已,所以可以通过减少关键路径上的组合逻辑单元数来减小该路径上的延时,从而达到优化的目的。关键路径重组是常用技术,多用于关键路径由多个路径组合而成的场合,而且这些被组合的路径之间又可以重组互相之间的相互顺序。

上图红色部分所示,这行代码需要在一个周期内完成加法,判断大小和与三个操作,组合逻辑的级数太大,成为了关键路径,

对于时序有一定的改善作用。

3. 适当地较少数据的位宽。

比如在上面代码中如果tx_cnt最大不超过2048,则可以将

signal tx_cnt: (15 downto 0) std_logic_vector ; 改为

signal tx_cnt: (10 downto 0) std_logic_vector ;

4. 充分利用二进制的优势,比如

通过判断计数器的寄存器counter的最高位来进行状态的跳转。

5. ddr3的前后通常有RAM作为数据的缓存,如果ram离ddr3的路径太长,容易导致时序变差。

解决办法有:

 A,将块ram变成分布式ram,因为块ram是在fpga中是固定位置。

 B, 多打几拍,相当于在路径中间设置几个加油站。

 

 

 

 

 

FPGA设计---时序分析 (内容来自https://blog.csdn.net/u012176730/article/details/54412323

 

STA(Static Timing Analysis,即静态时序分析)在实际FPGA设计过程中的重要性是不言而喻的,其作用是:

1. 帮助分析和验证一个FPGA设计的时序是否符合要求;

2. 指导fitter(布线综合器)布局布线出符合要求的结果;

启动沿:数据被launch的时钟边沿;也就是说,每一个启动沿,一般都会产生一个新的数据!

锁存沿:数据被latch的时钟边沿;也就是说,每一个锁存沿,都会有一个新的数据被保存!

对于如上图所示的级联的寄存器电路而言(忽略上一级触发器输出到下一级触发器输入之间的逻辑关系),一般蓝色的上升沿作为第一个触发器的启动沿,而红色的上升沿(一般都是紧跟着启动沿后的有效边沿)。所以说:蓝色的启动沿之后由REG1输出有效数据,并在红色的边沿被锁存进REG2并输出到下级。

上述的锁存沿会将数据保存下来,但是必须要满足一定的条件:

建立时间Tsu:在时钟有效沿之前,数据必须保持稳定的最小时间;

保持时间Th:在时钟有效沿之后,数据必须保持稳定的最小时间;

这就相当于一个窗口时间,在有效边沿的窗口时间内,数据必须保持稳定;这里的时钟信号时序和数据信号时序,都是寄存器实际感受到的时序;什么事实际感受到的,下面会继续分析;

1.3 数据到达时间(DAT:data arrival time)

所有的信号在FPGA内部传播都会有延时,包括时钟信号、数据信号(实际上不该如此可以的区分这两种信号,在一定条件下,这两个信号可能可以相互转换,这个是题外话了),也就是说,从信号的发出点到信号的接收点,会存在一个延时,这个延时可能是因为FPGA内部空间分布所致,也有可能是因为组合逻辑造成,这里不再深究;

正如上图所示,在计算数据到达时间时,一般都会存在3个延时:

1. Tclk1:时钟信号从起点(一般是PLL输出或者时钟输入引脚)到达启动寄存器(或说启动触发器)的相应clk端口所耗的时间;假如CLK是由PLL发出的时钟信号(称之为源时钟),这个信号经过FPGA内部的“连线”最终来到了REG1(启动触发器)的clk端,所以此时在REG的clk1处也会有周期性的时钟信号REG1.CLK(如图所示);可以看到,此时的CLK(源时钟)和REG1.CLK实际上有个(相位差)时间差,这个时间差就是Tclk1;

2. Tco:启动寄存器内部延时,是寄存器REG1感受到有效的上升沿后,到数据真正从从REG1的Q输出之间延时;请注意:上述所谓的有效的上升沿,就是REG1.CLK,而不是CLK;所以实际的有效数据输出的时序如上图的REG1.Q;

3. Tdata:数据从上级寄存器输出Q(经过所有其他组合逻辑以及FPGA内部走线)到下级寄存器的数据输入D之间的延时;如图所示,数据从从REG1的Q流向了REG2的D,所以REG2.D实际感受到的数据时序是REG2.D;

假如将上图中的launch Edge作为时间0点,将一些列的延时累加,所得结果称之为数据到达时间,DAT:

DAT=启动沿+Tclk1+Tco+Tdata;

析方法同上,需要计算数据建立时间,也需要两个延时:

1. Tclk2,不同于上述的Tclk1,这个延时是时钟从起点(一般是PLL或者时钟输入引脚)到锁存触发器之间的延时;如上图所示,REG2实际感受到的时钟来自于其本身的clk引脚,而不是源时钟CLK,他们之间存在一个延时,即Tclk2;所以REG2实际感受到的时钟,实际上是上图的REG2.CLK;

2. Tsu:上面分析过了,每一个数据被锁存都要满足建立时间和保持时间,Tsu就是建立时间,也就是在REG2实际感受到Latch Edge时,数据如果需要被正确锁存,就必须提前Tsu的时间来到REG2的D;

综合时钟走线延时Tclk2以及Tsu,我们得到了数据建立时间DRTsu:

DRTsu=锁存沿+Tclk2-Tsu。也就是说在DRTsu时刻之前,数据必须已经有效且稳定

即DRTh=锁存沿+Tclk2+Th;也就是说,数据在DRTh时间之前必须保持住不变;

如上图所示,在0时刻(Launch edge),源时钟CLK说,“啊,我要产生一个新的数据”,但是这个命令(启动沿)并没有马上传达到REG1,而是有个延时Tclk1。所以在Tclk1时刻,REG1终于听到了(感受到了有效的时钟上升沿,就是启动沿)老大的命令,就开始准备,他憋了一会儿,又延时了Tco,终于产生了数据(REG1.Q上有了valid data);这个有效数据也是慢吞吞的来到了他的终点,又浪费了Tdata。最终在Tclk1+Tco+Tdata时间后,REG2得到了这个数据;别以为REG2得到这个数据就完事了,REG2也是个傲娇的娃,怎么个傲娇法,下面继续分析;老大CLK在0时刻发送了启动沿之后,休息了一个时钟周期,在Latch edge时突然想起来,刚才让REG1发出的数据,REG2要接受啊,不然就浪费了,于是乎他又对REG2下达了命令,新数据要来了,准备好接受!但是这个命令也不是马上就到了REG2的耳中,而是经过了Tclk2的时间。等到REG2接收到命令后(实际感受到了有效的Latch Edge),他就看看自己家门口没有数据已经来了(检查REG2.D是否有数据),同时要看看这个数据是不是符合他的胃口的(满足锁存的条件),他要求数据必须在他接收到老大命令的时候已经等了Tsu时间(数据建立时间),由要求这个数据在他家门口不能早退,必要再保持Th时间(数据保持),如果都满足了,REG2就开心的接受了这个数据,反之,他就会觉得,REG1准备的数据太懒惰了(没有提前Tsu时间到达),又或者性子太急(没有多逗留th),一概不收!

所以这里涉及到两个要求,第一个就是建立时间裕量:

正如上图所示Setup Slack=DRTsu-DAT。

如果Setup Slack为正,则说明数据在规定的时间内达到了目标。反之,则认为数据并没有在规定的时间达到目标,此时REG2锁存的数据很有可能是亚稳态;

如上所述,hold slack = DAT – DRTh

如果为正,则认为数据在被锁存的时候有足够多的稳定时间,是有效的。反之则认为数据有误或者数据可能是亚稳态;

 

小结:

理解了上面的7个概念,就明白了:如果时钟频率过快或者数据延时太大,都会导致错误的时序。在FPGA内部寄存器到内部寄存器之间,所有的延时都是建立在时序模型上的,如slow和fast,这些模型从两个极端工作情况来分析FPGA能否正常工作;只要满足这两个工况,则FPGA在其他环境下都能满足时序!

 

现有一块ADC连接到FPGA上,需要在FPGA上实现高速数据的读取,那么第一步自然就是完成可靠的硬件连线,其中需要注意的是:

1. 注意信号的完整性,尽可能的避免边沿退化;这两区分两个概念:

    i. 高速信号,指的是信号翻转,由高电平到低电平或者反之所耗得时间非常小;可能一个1MHz的TTL信号或者LVDS信号,只要边沿足够陡,那也算是高速信号!

    ii. 高频信号,一般指的是周期性信号的周期时间足够小;

    iii. 也就是说高速信号不一定是高频的;数字信号一般都是高速信号,所以必须要保证其边沿的完整性,如果边沿发生退化或者变形,那么将相当于加入了额外的时序上的偏差;

2. 保持时钟信号和数据信号路径等长,不管是单端还是差分信号,需要用绕线等形式迫使两类线几乎等长;这个在之前的时序分析中非常重要,如果真的不能够做到等长,甚至差的还挺多的,也必须提前获得该差值,并将则合成时间差,在后面的时序分析中将会有用;

保证以上两点后,就可以着手时序的分析了,那么首先我们会得到目标器件ADC的时序,如下图所示:

从上图中我们首先得到几个信息:

1. 这是个同步时序,由两类信号组成,时钟信号DCO和数据信号FCO以及D(忽略它们是差分信号,下面的分析会把它画成单端信号,简化好画一点)

2. 这是个DDR信号,DDR指的是数据是同步于时钟信号的上升、下降边沿,所以该类同步信号需要引入虚拟时钟概念,后面继续介绍;

3. 信号是不是边沿对齐,而是偏移了90度!也就是说DCO边沿翻转后,数据信号没有第一时间翻转,而是延后了四分之一个周期,这是高速信号惯用的伎俩,后面会发现,这个延时让时序更好分析;

将FCO信号和D信号的实际意义扔一边,在设计者看来,他们都仅仅是数据而已,将上面的时序图简化成下图:

可以看到,实际上所有的数据信号都是同步于DCO的边沿,但是并不是对齐的,而是相差了90度,同时还是个DDR系统(上下边沿都是Launch Edge)

一般来说DDR系统会引入一个虚拟时钟的概念,就是说DCO是实际存在的时钟,设计和虚构出一个2倍频的DCOX2时钟,并将其相移180度以后,我们重新得到了下图:

引入虚拟时钟后,我们重新规划Launch Edge,将其规划到DCOX2-Shift180的上升沿,其所对应的的Latch Edge仍然还是在DCO上。

到目前为止,我们已经很清楚的规划了ADC的时钟和数据输出的关系,至于如何用SDC语言描述,见下文;接下来就要考虑到这些信号实际上是各自经过PCB走线后来到FPGA的引脚,从FPGA引脚由进入到FPGA内部,然后又经过各自的FPGA内部走线延时以后来到了他们目标的寄存器,如下图所示:

从上图可以获知:

1. ADC内部看起来有一个源时钟,这个源时钟我们不用管怎么产生,它分成了两路,其中一路经过倍频+移相后触发了ADC上的REG0(就是说其上升沿作为Launch Edge),另一路直接输出到ADC引脚DCO;

2. 数据由REG0产生后输出至ADC引脚D,经过一个延时后来到FPGA的相应输入引脚D`,与此同时,DCO引脚也经由PCB来到了FPGA的输入引脚DCO`;

3. 这两个信号进入FPGA后,都各自分成了两路,分别经过各自的延时来到其目标:

    a) DCO`引脚输入后,进过TCLK2,来到了REG1的clk引脚

    b) DCO`引脚输入后,进过TCLK3,来到了REG2的clk引脚

    c) D`引脚输入后,进过Tdata2,来到了REG1的D引脚

    d) D`引脚输入后,进过Tdata3,来到了REG2的D引脚

4. REG1和REG2有所区别,一个是上升沿触发,一个是下降沿触发(clk前加了个小圈圈),这是因为latch edge本来就是上升沿又有下降沿的;后期实际上也可以给DCO`也引入虚拟时钟,这里不表;

5. 不管是REG1还是REG2,想要锁存latch数据就必须满足建立时间和保持时间,这个在下文的图中也有所体现;

说了那么多,都不如实际的时序图来的实际,下面放图:

上图由三个颜色的时序,分别是:

1. 紫色代表DAT,也就是数据到达时间,它由Tco(图中没有体现,可以参考手册)、Tdata1和Tdata2三者构成,是不是和我们的DAT定义不一样?公式是死的,只需要理解其意思就可以。和公式相比少了Tclk(源时钟到REG0的clk的延时),是因为我们不需要考虑这个延时,我们是根据ADC数据手册的时序图反推回里面的结构图,所以所有延时在反推的过程中已经都被体现或者被折合!

2. 绿色伙同棕色线,表达出两个意思DRTsu和DRTh,分别代表数据建立所需时间和数据保持所需时间;

3. 将两者按照定义做减法,就能够得到建立时间裕量和保持时间裕量!

如上图所示,棕色线所划分的时间窗中,REG1.D已经是新的数据,而且在这个时间窗内并没有变化,所以就同时满足了建立时间裕量大于0和保持时间裕量大于0两个关系,这样的时序是稳定的!

但是这个只是图示而已,所有的Tdata1、2、3以及Tclk1、2、3都是我们目前假设的,在实际进行约束时,那些量时需要设计者提前设定,而那些量是自动生成的那?答案是:

1. Tdata1和Tclk1是由PCB实际布线所决定的,如果能够按照等长布线规则,就能够让两者相互抵消;

2. DCO和DCOX2-shift180的时序是由器件决定的;

3. Tdata2、3,Tclk2、3是FPGA在布线时自动产生的!

所以说这里我们只需要告诉FPGA,DCO`和D`之间的时序关系就可以了,要获得这两者之间的时序关系,我们就必须获得DCO和D之间的原始关系,以及他们是如何被布线延时变成DCO`和D`的;如何去描述上面所说的这种关系呢?利用SDC文件!

也就是说SDC文件就是要准确的告诉FPGA,所有输入(输出先不管)信号在进入FPGA时会是个什么样子,然后根据这个信息,FPGA会自动布线,使得REG1和REG2能够获得正确的数据;如果万一SDC文件所描述的时序关系非常的恶劣,将会导致不管FPGA怎么优化布线和布局,都不能够实现正确时时序时,就会输出报错,这个在以后的文章TimeQuest TA中会有详细的分析;那么接下来就开始写SDC文件吧;

#设置各种延时常数

#这里假设ADC片上的延时都为0

    set ADC_CLKs_max 0

    set ADC_CLKs_min 0

    Set ADC_CLKd_max 0

    set ADC_CLKd_min 0

# 同时根据ADC手册去设置Launch edge到有效数据之间的延时,这里假设他为X

    set ADC_tCO_max X

    set ADC_tCO_min X

#这里设置时钟信号和数据信号在PCB板上的延时差,即使是等长布线,我们也要可以给

#定两个值,这样可以给FPGA布线更多的压力,使得后期布线会往一个最理想的方向进行,

#分别是

    set ADC_BD_min XX

    set ADC_BD_max XX

 

 

#设置两个时钟,第一个时钟为DCO,它会从FPGA的DCO引脚输入

#另一个时钟是虚拟时钟,根据设置,它是DCO的两倍频,而且有180度的相移

#这两个时钟之间是同步的,一个是很是存在的,另一个是虚拟的!

    create_clock -name DCO-period 5-waveform {1.25   3.75} [get_ports {DCO}]

    create_clock -name DCO_virtual-period 2.5 -waveform {0    1.25}

 

 

#最后将所有的数据引脚同步到DCO_virtual的上升沿,根据上面的延时常数设置输入延时和

#输出延时,这条语句非常关键,它告诉FPGA所有的输入信号,在进入FPGA之前,相对于

#时钟存在怎么样的关系!

    set_input_delay -clock DCO_virtual -max [expr $ADC_CLKs_max + $ADC_tCO_max + $ADC_BD_max - $ADC_CLKd_min] [get_ports {D*}]

    set_input_delay -clock DCO_virtual -min [expr $ADC_CLKs_min + $ADC_tCO_min + $ADC_BD_min - $ADC_CLKd_max] [get_ports {}D*}]

 

SDC文件解释

1. 蓝色底部分代表定义一些延时参数,这些延时参数都是根据实际的PCB布线或者是ADC的书籍参数来设定的

2. 绿色底部分设定同步时钟,如果有必要的话还要设置虚拟时钟;

3. 紫色底部分将所有的输入信号同步到时钟,在这里这个时钟是虚拟时钟,因为我们假设虚拟时钟的上升沿是launch edge,这里其实可以也可以同步到DCO上,但就要设置下降沿同步,会显得比较麻烦;但是一样都是可以实现的!

通过上面的语句,FPGA就知道了,这些属于信号之间的关系:D和DCO之间的关系,D和DCOX2-shift180(就是DCO_Virtual)之间关系;

 



对自己的设计的实现方式越了解,对自己的设计的时序要求越了解,对目标器件的资源分布和结构越了解,对EDA工具执行约束的效果越了解,那么对设计的时序约束目标就会越清晰,相应地,设计的时序收敛过程就会更可控。 riple

    从最近一段时间工作和学习的成果中,我总结了如下几种进行时序约束的方法。按照从易到难的顺序排列如下: riple

 

0. 核心频率约束

    这是最基本的,所以标号为0。 riple

1. 核心频率约束+时序例外约束

    时序例外约束包括FalsePath、MulticyclePath、MaxDelay、MinDelay。但这还不是最完整的时序约束。如果仅有这些约束的话,说明设计者的思路还局限在FPGA芯片内部。 riple

2. 核心频率约束+时序例外约束+I/O约束

    I/O约束包括引脚分配位置、空闲引脚驱动方式、外部走线延时(InputDelay、OutputDelay)、上下拉电阻、驱动电流强度等。加入I/O约束后的时序约束,才是完整的时序约束。FPGA作为PCB上的一个器件,是整个PCB系统时序收敛的一部分。FPGA作为PCB设计的一部分,是需要PCB设计工程师像对待所有COTS器件一样,阅读并分析其I/O Timing Diagram的。FPGA不同于COTS器件之处在于,其I/O Timing是可以在设计后期在一定范围内调整的;虽然如此,最好还是在PCB设计前期给与充分的考虑并归入设计文档。 riple

    正因为FPGA的I/O Timing会在设计期间发生变化,所以准确地对其进行约束是保证设计稳定可控的重要因素。许多在FPGA重新编译后,FPGA对外部器件的操作出现不稳定的问题都有可能是由此引起的。 riple

3. 核心频率约束+时序例外约束+I/O约束+Post-fit Netlist

    引入Post-fit Netlist的过程是从一次成功的时序收敛结果开始,把特定的一组逻辑在FPGA上实现的布局位置和布线结果固定下来,保证这一布局布线结果可以在新的编译中重现,相应地,这一组逻辑的时序收敛结果也就得到了保证。由于有了EDA工具的有力支持,虽然是精确到门级的细粒度约束,设计者只须进行一系列设置操作即可,不需要关心布局和布线的具体信息。 riple

4. 核心频率约束+时序例外约束+I/O约束+LogicLock

    LogicLock是FPGA器件内部的布局约束。LogicLock的约束是粗粒度的,只规定设计顶层模块或子模块可以调整的布局位置和大小。成功的LogicLock需要设计者对可能的时序收敛目标作出预计,考虑特定逻辑资源(引脚、存储器、DSP)与LogicLock Region的位置关系对时序的影响,并可以参考上一次时序成功收敛的结果。这一权衡和规划FPGA底层物理布局的过程就是FloorPlanning。LogicLock给了设计者对布局位置和范围更多的控制权,可以有效地向EDA工具传递设计者的设计意图,避免EDA工具由于缺乏布局优先级信息而盲目优化非关键路径。由于模块在每一次编译中的布局位置变化被限定在了最优的固定范围内,时序收敛结果的可重现性也就更高。 riple

5. 核心频率约束+时序例外约束+I/O约束+寄存器布局约束

    寄存器布局约束是精确到寄存器或LE一级的细粒度布局约束。设计者通过对设计施加精准的控制来获得可靠的时序收敛结果。对设计中的每一个寄存器手工进行布局位置约束并保证时序收敛是一项浩大的工程,这标志着设计者能够完全控制设计的物理实现。这是一个理想目标,是不可能在有限的时间内完成的。通常的做法是设计者对设计的局部进行寄存器布局约束并通过实际运行布局布线工具来获得时序收敛的信息,通过数次迭代逼近预期的时序目标。 riple

    不久前我看到过一个这样的设计:一个子模块的每一个寄存器都得到了具体的布局位置约束。该模块的时序收敛也就相应地在每一次重新编译的过程中得到了保证。经过分析,这一子模块的设计和约束最初是在原理图中进行的,在达到时序收敛目标后该设计被转换为HDL语言描述,相应的约束也保存到了配置文件中。 riple

6. 核心频率约束+时序例外约束+I/O约束+特定路径延时约束

    好的时序约束应该是“引导型”的,而不应该是“强制型”的。通过给出设计中关键路径的时序延迟范围,把具体而微的工作留给EDA工具在该约束的限定范围内自由实现。这也是一个理想目标,需要设计者对每一条时序路径都做到心中有数,需要设计者分清哪些路径是可以通过核心频率和简单的时序例外约束就可以收敛的,哪些路径是必须制定MaxDelay和MinDelay的,一条也不能遗漏。设定路径延时约束就是间接地设定布局布线约束,但是比上述3、4、5的方法更灵活,而且不失其准确性。通过时序约束而不是显式的布局和网表约束来达到时序收敛才是时序约束的真谛。 riple

 

    记得有网友说过“好的时序是设计出来的,不是约束出来的”,我一直把这句话作为自己进行逻辑设计和时序约束的指导。好的约束必须以好的设计为前提。没有好的设计,在约束上下再大的功夫也是没有意义的。不过,通过正确的约束也可以检查设计的优劣,通过时序分析报告可以检查出设计上时序考虑不周的地方,从而加以修改。通过几次“分析—修改—分析”的迭代也可以达到完善设计的目标。应该说,设计是约束的根本,约束是设计的保证,二者是相辅相成的关系。

 

 

调试flash,ddr3 ,sdram,跨时钟域,边缘闪红点打拍走PIO,  fifo溢出导致图像闪点

调试中遇到的bug主要份两类

 1, 逻辑或者时序的问题(逻辑上的问题比较好解决,主要是时序和资源的问题,优化资源和时序)

2, pcb硬件的问题(电源的问题,serdes的p,n管脚接反了,sdramd的ba管脚没接)

 

 

 

猜你喜欢

转载自blog.csdn.net/walkmaner/article/details/84200082
今日推荐