数字 08 vivado的时序约束UI界面操作

实例1 ADC input_delay

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

 

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

 

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

 

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

 

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

 

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

 

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

 

数字 08 vivado的时序约束UI界面操作 图 1 某ADC的时序图

 

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

 

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

 

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

 

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

 

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

 

数字 08 vivado的时序约束UI界面操作

图 2 简化后的时序图

 

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

 

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

 

数字 08 vivado的时序约束UI界面操作

 

图 3 引入虚拟时钟后的数据时序图

 

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

 

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

 

数字 08 vivado的时序约束UI界面操作

图 4 傻瓜化后的ADC和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数据就必须满足建立时间和保持时间,这个在下文的图中也有所体现;

 

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

数字 08 vivado的时序约束UI界面操作

图 5 实际时序分析

 

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

 

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实际布线所决定的,如果能够按照等长布线规则,就能够让两者相互抵消;

数字 08 vivado的时序约束UI界面操作数字 08 vivado的时序约束UI界面操作

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

 

数字 08 vivado的时序约束UI界面操作

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

数字 08 vivado的时序约束UI界面操作

所以说这里我们只需要告诉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,它会从FPGADCO引脚输入

#另一个时钟是虚拟时钟,根据设置,它是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)之间关系;

 

————————————————

版权声明:本文为****博主「禾刀围玉」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.****.net/u012176730/article/details/54426491

 

实例2 wave_gen

主时钟

输入report_clock_networks -name main

查看主时钟约束情况

数字 08 vivado的时序约束UI界面操作

其中 clk_pin_p是mmcm输出的自动约束了,我们主需要约束clk_in2

在tcl中键入

create_clock -name clk2 -period 25 [get_ports clk_in2]

 

所以 主时钟的约束指令是

Create_clock –name 时钟名字 –period 周期 时钟自哪个点输出

主时钟约束完成

 

衍生时钟

数字 08 vivado的时序约束UI界面操作

数字 08 vivado的时序约束UI界面操作

分析一共有四个衍生时钟,但是其中有两个是mmcm组合出来的,不用我们手动约束,我们需要手动约束的是clk_samp和spiclk

 

Clk_samp在模块clk_gen_i0这个模块里面,

数字 08 vivado的时序约束UI界面操作

在clk_gen.v中有它的连接方式,是从BUFHCE_clk_samp_i0/O端口输出的一个时钟

create_generated_clock -name clk_samp -source [get_pins clk_gen_i0/clk_core_i0/clk_tx] -divide_by 32 [get_pins clk_gen_i0/BUFHCE_clk_samp_i0/O]

 

create_generated_clock -name spi_clk -source [get_pins dac_spi_i0/out_ddr_flop_spi_clk_i0/ODDR_inst/C] -divide_by 1 -invert [get_ports spi_clk_pin]

 

所以 衍生时钟的约束指令是

Create_generated_clock –name 时钟名字 –source 时钟的来源 –divide_by xx 时钟自哪个点输出(port或者pin)

 

至此,衍生时钟创建完毕

 

如果需要改衍生时钟的名字,它的格式是

Create_generated_clock –name 时钟名字 时钟源 时钟输出点

 

延迟约束

延迟约束主要根据以下表格进行

数字 08 vivado的时序约束UI界面操作

对于输入管脚,首先判断捕获时钟是主时钟还是衍生时钟,如果是主时钟,直接用set_input_delay即可,如果是衍生时钟,要先创建虚拟时钟,然后再设置delay。对于输出管脚,判断有没有输出随路时钟,若有,则直接使用set_output_delay,若没有,则需要创建虚拟时钟。

 

Rxd_pin只跟随主时钟,直接用set input_delay就可以

set_input_delay -clock [get_clocks -of_objects [get_ports clk_pin_p]] 0.000 [get_ports rxd_pin]

set_input_delay -clock [get_clocks -of_objects [get_ports clk_pin_p]] -min -0.500 [get_ports rxd_pin]

 

对于txd_pin和lb_sel_pin需要创建虚拟时钟

create_clock -period 6.000 -name virtual_clock

set_input_delay -clock virtual_clock -max 0.000 [get_ports lb_sel_pin]

set_input_delay -clock virtual_clock -min -0.500 [get_ports lb_sel_pin]

set_output_delay -clock virtual_clock -max 0.000 [get_ports {txd_pin {led_pins[*]}}]

set_output_delay -clock virtual_clock -min -0.500 [get_ports {txd_pin {led_pins[*]}}]

 

对于spi_mosi_pin,不需要虚拟时钟,直接用set_output_delay即可

set_output_delay -clock spi_clk -max 1.000 [get_ports {spi_mosi_pin dac_cs_n_pin dac_clr_n_pin}]

set_output_delay -clock spi_clk -min -1.000 [get_ports {spi_mosi_pin dac_cs_n_pin dac_clr_n_pin}]

 

dac_*和led_pins没有进行约束

 

 

多周期路径约束

  多周期路径,我们一般按照以下4个步骤来约束:

1 带有使能的数据

  首先来看带有使能的数据,在本工程中的Tming Report中,也提示了同一个时钟域之间的几个路径建立时间不满足要求

2 两个有数据交互的时钟之间存在相位差

3 存在快时钟到慢时钟的路径

4 存在慢时钟到快时钟的路径

 

 

 

实例3 spi

 

数字 08 vivado的时序约束UI界面操作

进行约束的是这个工程

约束前的时序情况是:

数字 08 vivado的时序约束UI界面操作

看到 setup slack不足

数字 08 vivado的时序约束UI界面操作

工程情况

在tcl命令框里面输入report_clock networks -name mainclock

数字 08 vivado的时序约束UI界面操作

出现这样的情况

数字 08 vivado的时序约束UI界面操作

其中

主时钟clk156p已经被约束

 

查看时序问题报告

数字 08 vivado的时序约束UI界面操作 时序问题主要发生在inter_clock paths也就是时钟之间的路径上

数字 08 vivado的时序约束UI界面操作

点进去时序约束的界面,看见slack的实际情况

 

 

数字 08 vivado的时序约束UI界面操作 如上图所示,我为30m到10m时钟进行了一个多周期路径约束之后,30m到10m的时序就满足要求了,所以这设计的主要时序问题是多时钟之间的路径问题。

数字 08 vivado的时序约束UI界面操作

这两个信号按照频率来说都是uart时钟的1/176,也就是153.6k/176=0.87KHz,周期是1145760

clkout是从pll出来的40m时钟又分频之后的时钟,频率是153.6KHz 周期是6510ns

workclk是spi工作时钟,最高频率40M  周期是25ns 是从pll出来之后又分频的

 

这几个时钟都是衍生时钟

 

先对rdidle进行约束

它的源是clkout,

数字 08 vivado的时序约束UI界面操作

源的点是在 uart_top/div/clkout_reg/Q

然后是自己输出的点uart_top/rdidle_reg/Q

数字 08 vivado的时序约束UI界面操作

所以最后的约束时这样子的

数字 08 vivado的时序约束UI界面操作

 

约束完了之后,用tcl命令report_clocks看一下约束情况

数字 08 vivado的时序约束UI界面操作

 

然后时rdstart

数字 08 vivado的时序约束UI界面操作

我约束完rdidle之后rdstart就不见了,不知道为啥?

 

约束clkout

他的源头时40M时钟

数字 08 vivado的时序约束UI界面操作

 

继续 workclk

 

 

 

 

 

/*

**=============================================================

**   

**    这部分是已经被约束的引脚和时钟,我将在此基础上进行进一步的

**    时序约束

**   

**=============================================================

*/

set_property IOSTANDARD LVCMOS33 [get_ports I_clk]

set_property IOSTANDARD LVCMOS33 [get_ports I_rst_n]

set_property IOSTANDARD LVCMOS33 [get_ports I_spi_miso]

set_property IOSTANDARD LVCMOS33 [get_ports O_spi_cs]

set_property IOSTANDARD LVCMOS33 [get_ports O_spi_mosi]

set_property IOSTANDARD LVCMOS33 [get_ports O_spi_sck]

set_property PACKAGE_PIN K28 [get_ports I_clk]

set_property PACKAGE_PIN Y29 [get_ports I_rst_n]

set_property PACKAGE_PIN AA27 [get_ports I_spi_miso]

set_property PACKAGE_PIN AA25 [get_ports O_spi_cs]

set_property PACKAGE_PIN AB28 [get_ports O_spi_mosi]

set_property PACKAGE_PIN AB25 [get_ports O_spi_sck]

set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub]

set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub]

set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub]

connect_debug_port dbg_hub/clk [get_nets I_clk_IBUF_BUFG]

 

set_property PACKAGE_PIN K28 [get_ports I_clk_p]

set_property IOSTANDARD LVDS_25 [get_ports I_clk_p]

set_property PACKAGE_PIN W29 [get_ports addra]

set_property PACKAGE_PIN AA28 [get_ports addrb]

set_property IOSTANDARD LVCMOS33 [get_ports addra]

set_property IOSTANDARD LVCMOS33 [get_ports addrb]

 

set_property IOSTANDARD LVDS_25 [get_ports clk156p]

set_property PACKAGE_PIN K28 [get_ports clk156p]

set_property PACKAGE_PIN M19 [get_ports rd]

set_property IOSTANDARD LVCMOS33 [get_ports tx]

set_property PACKAGE_PIN K24 [get_ports tx]

set_property PACKAGE_PIN Y29 [get_ports rst_n]

set_property IOSTANDARD LVCMOS33 [get_ports rd]

set_property IOSTANDARD LVCMOS33 [get_ports rst_n]

 

 

 

/*

**=============================================================

**   

**    这部分是后来进行的时序约束

**   

**=============================================================

*/

//约束rdidle信号

create_generated_clock -name rdidle -source [get_pins uart_top/div/clkout_reg/Q] -divide_by 176 [get_pins uart_top/rdidle_reg/Q]   

//约束clkout

create_generated_clock -name clkout -source [get_pins spitop/clkpll/inst/plle2_adv_inst/CLKOUT3] -divide_by 260 [get_pins uart_top/div/clkout_reg/Q]   

//约束workclk

create_generated_clock -name workclk -source [get_pins spitop/clkpll/inst/plle2_adv_inst/CLKOUT3] -divide_by 1 [get_pins spitop/divspi/workclk_reg/Q]   

 

set_multicycle_path 3 -setup -start -from [get_clocks clk30m_clk_wiz_0] -to [get_clocks clk10m_clk_wiz_0]

 

set_multicycle_path 2 -hold -from [get_clocks clk30m_clk_wiz_0] -to [get_clocks clk10m_clk_wiz_0]

 

 

 

分析set_multicycle_path

数字 08 vivado的时序约束UI界面操作

 

这条路径的出错原因是,数据从div_counert_reg[21]/C出发,到div_counter_reg[5]/R端口,这条路径上的总延迟有4.107ns,有点大,然后导致setup slack小于0,并且,这条路径实际上是从10m时钟下的触发器到20m时钟下的触发器,是一个跨时钟域的路径。

我想要的效果是,让建立时间裕量更加宽裕一些。

我认为有几种方法:

·减少这条路径上组合逻辑的延迟。

·使用set_multicycle_path进行多周期约束

·直接去除掉了这个选择时钟的功能

 

数字 08 vivado的时序约束UI界面操作

我对inclk设置了一个40m的约束,它说我的余量是22ns左右

数字 08 vivado的时序约束UI界面操作

所以是我对inclk没有设置约束的原因,导致软件并不知道inclk到底是多少频率。所以说我的建立时间余量不够,实际上是完全够的。

 

 

 

实例4 分析500m时的时序情况(250m时未出现时序问题)

PLL自动生成的时钟约束

数字 08 vivado的时序约束UI界面操作

 

数字 08 vivado的时序约束UI界面操作

 

数字 08 vivado的时序约束UI界面操作

 

数字 08 vivado的时序约束UI界面操作

按照名词顺序开始分析,

首先,出现时序约束的路径是path21。

时序裕量是-1.46ns,也就是说不符合时序要求。

路径源是divnumtemp_reg Q端

路径目的地是div_counter_reg R端 这两个端口都是时钟500m驱动

路径组是500m

路径类型是建立 ()

时序要求是2ns 也就是500m的rise到rise,也就是一个周期

数据路径延迟是2.99ns 其中logic延迟0.857,路径延迟是2.133ns

路径上的逻辑块有6个   3个carry4超前进位加法器   3个LUT查找表

时钟偏斜-0.021ns

时序不确定度,可以用于附加时序余量 margin

 

数字 08 vivado的时序约束UI界面操作

                                                                                                                 

 

 

实例5 利用vivado的UI时序约束向导进行约束

在什么都没有做的时候,时序约束UI界面里面是这样的

数字 08 vivado的时序约束UI界面操作

里面有一个主时钟clk156p,一个input jitter ,都是关于PLL的输入主时钟的,既然他已经做好了,而且我也明确的知道,这是一个port进来的主时钟,并且这个时钟是锁定住的,时钟约束的开头有个锁,所以我不能再对他进行操作。

所以我要在这基础上,进行我的时钟约束。

首先梳理我的时钟树

数字 08 vivado的时序约束UI界面操作

其实很简单,我需要约束的时钟是4个

1、主时钟clk156p

2、衍生时钟clk500m

3、衍生时钟clk40m

4、workclk是clk500m的分频

 

其中,1已经做好了,现在开始做第二个

数字 08 vivado的时序约束UI界面操作

点击+号

数字 08 vivado的时序约束UI界面操作

取个名字,然后点击右边的...

数字 08 vivado的时序约束UI界面操作

数字 08 vivado的时序约束UI界面操作

查找他的上级时钟

数字 08 vivado的时序约束UI界面操作

点击箭头放到右边 然后ok

然后是master clock(这里应该理解成上级时钟)

数字 08 vivado的时序约束UI界面操作

是主时钟,写好如下

数字 08 vivado的时序约束UI界面操作

这里有个问题,衍生时钟只能是主时钟的整数倍频或者分频

然后是source objects

数字 08 vivado的时序约束UI界面操作

这个是本时钟的路径,也就是clk500m的路径

点击-add

数字 08 vivado的时序约束UI界面操作

这样,他就约束好了,但是我们的500m并不是主时钟的整数倍频或者分频,所以这个还需要进一步探讨