Vivado时序约束
本文主要介绍如何在Vivado设计套件中进行时序约束,原文出自Xilinx中文社区。
1 Timing Constraints in Vivado -UCF to XDC
Vivado软件相比于ISE的一大转变就是约束文件,ISE软件支持的是UCF(User Constraints File),而Vivado软件转换到了XDC(Xilinx Design Constraints)。XDC主要基于SDC(Synopsys Design Constraints)标准,另外集成了Xilinx的一些约束标准,可以说这一转变是Xilinx向业界标准的靠拢。Altera从TimeQuest开始就一直使用SDC标准,这一改变,相信对于很多工程师来说是好事,两个平台之间的转换会更加容易些。首先看一下业界标准SDC的原文介绍:
Synopsys' widely-used design constraints format, known as SDC, describes the "design intent" and surrounding constraints for synthesis, clocking, timing, power, test and environmental and operating conditions. SDC has been in use and evolving for more than 20 years, making it the most popular and proven format for describing design constraints. Essentially all synthesized designs use SDC and numerous EDA companies have translators that can read and process SDC.
Xilinx原先的自成一派(UCF)其实其实也算做的不错,相信使用过UCF的工程师也有同感,并没有什么不便。像Apple那样软件和硬件都自成一派而且能与其它所有派别抗衡的,背后需要有多强大的团队支持,可能Xilinx可是考虑到这点,不想花费过多的精力去维护。(个人见解)
文归正题,如果有读者以前没有使用XDC/SDC的经验,这边讲解一下如何从UCF到XDC的转换。如图1所示为UCF与SDC的约束命令比较,可以发现常用的命令都能对应上。
图1
下面简单举例说明:
Clock Period:
UCF :NET "clka" TNM_NET = "clka";
TIMESPEC "TS_clka" = PERIOD "clka" 13.330 ns HIGH 50.00%;
XDC :create_clock -name clka -period 13.330 -waveform {0 6.665} [get_ports clka]
Input Port:
UCF :OFFSET = IN 8 BEFORE clka;
XDC :set_input_delay -clock clka 2 [all_inputs]
注: clock period = 10 ns.
Output Port:
UCF :OFFSET = OUT 12 AFTER clkc;
XDC :set_output_delay -clock clkc 8 [all_outputs]
注:clock period = 20 ns.
除了以上约束命令的差别外,UCF和XDC间的主要差别如下:
1. XDC是顺序执行约束,每个约束指令有优先级
2. UCF一般约束nets对象,而XDC约束类型是pins, ports和cells对象
3. UCF约束默认不对异步时钟间路径进行时序分析,而XDC约束默认所有时钟是相关的,会分析所有路径,可以通过设置时钟组(set_clock_groups)取消时钟间的相关性。
下面介绍一下在Vivado中添加XDC文件以及加入约束命令的方法:
首先在Project Manager中展开Constraints类,选择Add Sources即可添加或者新建XDC约束文件,如图2所示。
图2
选择新建的XDC文件,双击打开,选择左侧的Templates,其中有XDC约束命令的实例,所有的约束命令都可以在其中找到,非常方便,如图3,4所示。
图3
图4
XDC约束文件可以在编译综合和实现过程中使用时,在综合和实现设置中都能选择需要的约束,如图5。通过创建约束文件集,如图6,设计者可以使能不同的约束集合测试FPGA设计的性能;在约束文件集中可以包含多个XDC约束文件,在FPGA设计比较复杂时,可以分模块或者IP核约束,相应的则有多个XDC约束文件,这样设计和维护效率都能得到提高。
图6
2 Timing Constraints in Vivado -- 2. Timing Basics
在深入讲解XDC约束前,先介绍一下基本的时序约束、分析的概念。
2.1 Timing Path:
图1中包含了主要的时序分析路径:
1. 输入端口到FPGA内部时序单元的路径
2. FPGA内部时序单元间的路径
3. FPGA内部时序单元到输出端口的路径
4. 输入端口到输出端口的路径
图1
不管时序单元是在FPGA内部还是外部,除了第4条路径,它是从输入端口到输出端口,其间没有锁存,其它3条路径的时序分析都以2个时序单元间的路劲进行分析,如图2所示。
第一个时序单元上的时钟称为source clock(启动时钟),第二个时序单元上的时钟称为destination clock(锁存时钟),时序分析从source clock的上升沿开始,到之后的destination clock的上升沿结束,时序分析的过程就是检验数据在两个上升沿时间差内经过数据路径传输后是否满足要求,数据到达时需要满足后一级时序单元的setup/hold要求,其本质上是需要数据在到达后一级时序单元时不发生亚稳态,数据能够被稳定地采集到并且稳定地输出。
图2
2.2 Clock Setup Check:
检验Setup是否满足要求,这边引入setup slack概念,只要setup slack的值大于零即Setup检查满足要求,其计算公式如下:
setup slack = data required time – data arrival time
其中:
data required time=destination clock edge time + destination clock path delay
- clock uncertainty- setup time
data arrival time = source clock edge time + source clock path delay
+ clock to output time + data path delay
公式代入可得到:
setup slack = (destination clock edge time - source edge time)
+ (destination clock path delay - source clock path delay)
- clock uncertainty - setup time - clock to output time - data path delay
= T¬destination_to_source + (Tclk-D2 – Tclk-D1) – Tclk_uncertainty – Tsetup – uTco - Tdata_path_delay
在Setup检查中source clock一定超前于destination clock。
其中第一部分T¬destination_to_source,当source clock和destination clock为异步时钟时,如图3中实例,source clock的周期等于6ns,destination clock的周期等于4ns,首先假定2个时钟的相位差为0,图中在这种情况下有2个setup关系,setup1下T¬destination_to_source = 4ns,setup2下T¬destination_to_source = 2ns,在实际分析中应该选取最严格的情况,即选取setup2这种。
图3
而当source clock和destination clock为同一个时钟时,T¬destination_to_source的值很显然就是时钟周期Tclk_period,这也是时序分析最多的情况了,进一步推导setup slack = T¬clk_period+ (Tclk-D2– Tclk-D1) – Tclk_uncertainty - Tsetup – Tdata_path_delay > 0,可以得到:
T¬clk_period > Tclk_uncertainty + Tsetup + Tdata_path_delay - (Tclk-D2 – Tclk-D1)
T¬clk_period、Tclk_uncertainty可以通过时序约束确定其值,uTco, Tsetup是时序单元的属性值,(Tclk-D2 – Tclk-D1)在布局布线后其值也能确定,剩下Tdata_path_delay对T¬clk_period影响最大,一个设计Setup检查中的关键路径往往是Tdata_path_delay值最大的一条路径,影响其值有很多原因,如逻辑级数过多,扇出导致布线延时过大…
2.3 Clock Hold Check:
对应Hold检查,也有hold slack,其计算公式如下:
hold slack = data arrival time – data required time
其中
data required time = destination clock edge time + destination clock path delay
+ clock uncertainty + hold time
data arrival time = source edge time + source clock path delay
+ clock to output time + data path delay
代入公式得到:
hold slack = (source clock edge time - destination edge time)
+(source clock path delay - destination clock path delay)
- clock uncertainty - hold time + clock to output time + data path delay
=T¬source_to_destination + (Tclk-D1 – Tclk-D2) – Tclk_uncertainty – Thold + uTco + Tdata_path_delay
与Setup检查不同,在Hold检查下destination clock超前于source clock。在Setup检查中,T¬destination_to_source的值选取destination clock和source clock相差最小的情况下进行分析;而Hold检查中T¬source_to_destination的值选取所有Setup关系分别进行分析,每一种Setup关系对应有两种情况,然后选取所有情况中T¬destination_to_source值大的计算对应的T¬source_to_destination
a. 取Setup关系的前一个destination clock沿,如图4中Hold1a和Hold2a
b. 取Setup关系的destination clock沿,如图4中Hold1b和Hold2b
图4
根据图4中实例计算得到:
Hold1a:T¬destination_to_source= 0ns
Hold1b:T¬destination_to_source= -2ns
Hold2a:T¬destination_to_source= -2ns
Hold2b:T¬destination_to_source= -4ns
显然选取Hold1a,对应T¬source_to_destination值为0ns
当source clock和destination clock为同一个时钟时,可以计算得到:
T¬source_to_destination值为0ns,进一步推导
hold slack = T¬source_to_destination + (Tclk-D1 – Tclk-D2) – Tclk_uncertainty – Thold+ Tdata_path_delay > 0可以得到:
Tdata_path_delay >Tclk_uncertainty + Thold + (Tclk-D2 – Tclk-D1)
由上得出数据路径的延时也不能过短,与Setup检查是矛盾对立的存在;在FPGA设计或者数字前端开发时,工程师考虑最多的是Setup是否满足要求,而Hold检查的工作主要交给工具或者负责数字后端的工程师解决。
2.4 Timing Report in Vivado:
下面通过简单的实例说明一下vivado中的时序分析,当FPGA设计经过综合实现后,通过Report Timing Summary打开时序报告,如图5、6所示。
图5
图6
图中有红色部分表示设计中有时序不满足要求,此例中是Setup。选择Setup中未满足要求的Path,打开Path Properties,如图7所示。
图7
Setup关键路径的时序报告如图8所示,报告由四部分组成:Summary, Source Clock Path, Data Path和Destination Clock Path,其中由Source Clock Path和Data Path得出Arrival Time,由Destination Clock Path得出Required Time。
图8
Hold检查的报告也类似,如图9所示。
图9
3 Timing Constraints in Vivado -- 3. Define Clocks
Vivado进行时序分析,对时钟的约束是必不可少的,设计中的时钟可分为一下几种:
① Primary Clocks 主时钟;
② Generated Clocks 衍生时钟;
③ Virtual Clocks 虚拟时钟。
3.1 Primary Clocks
主时钟一般是FPGA外部芯片如晶振提供的时钟,通过FPGA引脚输入。Vivado进行时序分析时,以主时钟的源端点作为延时计算起始点(0ns点)。主时钟的约束命令如下:
create_clock-name <clock_name> -period <period> -waveform {<rise_time> <fall_time>} [get_ports <input_port>]
下面通过几个实例说明一下约束命令:
a.
create_clock-name clk_main -period 10 -waveform {0 5} [get_ports GCLK]
周期10ns,0ns上升沿,5ns下降沿。
b.
create_clock-name clk_main -period 10 -waveform {0 2.5} [get_ports GCLK]
周期10ns,0ns上升沿,2.5ns下降沿;与a例周期相同,但是占空比不同,a例中50%,b例中25%。
c.
create_clock-name clk_main -period 20 -waveform {0 10} [get_ports GCLK]
周期20ns,0ns上升沿,10ns下降沿;与a例占空比相同,都是50%,但是周期不同,a例中10ns,b例中20ns。
3.2 Generated Clocks
衍生时钟是由设计内部产生,一般由时钟模块(MMCM or PLL)或者逻辑产生,并且对应有一个源时钟,源时钟可以是系统的主时钟或者另外一个衍生时钟。约束衍生时钟时,除了定义周期,占空比,还需要指明与源时钟的关系。通过create_generated_clock命令约束衍生时钟,命令如下:
create_generated_clock -name<generated clock name> -source <master clock source pin or port> -divide_by <div_factor> <pin_or_port>
a.
图 1
如图1中,主时钟GCLK通过PLL产生两个衍生时钟CLKOUT1和CLKOUT2,其中GCLK—100MHz,CLKOUT1—100MHz,CLKOUT2—10MHz,对于MMCMx, PLLx, BUFR primitives这几种时钟模块,Vivado会自动对主时钟和衍生时钟进行约束。
在Tcl Console中输入report_clocks可以得到时钟报告,以下是未对设计进行任何时钟约束的情况:
report_clocks
INFO: [Timing 38-35] Done setting XDC timing constraints.
INFO: [Timing 38-2] Deriving generated clocks
***************************************************************************
* Report : Clocks
* Design : top
* Part : Device=7z020, Package=clg484, Speed=-1
* Version : Vivado v2013.1 Build 248050 by xbuild on Wed Mar 27 17:27:24 MDT 2013
* Date : Tue Dec 17 12:17:09 2013
***************************************************************************
Attributes
P: Propagated
G: Generated
V: Virtual
I: Inverted
Clock Period Waveform Attributes Sources
clk_in1 10.00000 {0.00000 5.00000} P {GCLK}
clkfbout_clk_gen 10.00000 {0.00000 5.00000}
P,G {clk_gen_u/inst/plle2_adv_inst/CLKFBOUT}
clk_out1_clk_gen 20.00000 {0.00000 10.00000}
P,G {clk_gen_u/inst/plle2_adv_inst/CLKOUT0}
clk_out2_clk_gen 100.00001 {0.00000 50.00000}
P,G {clk_gen_u/inst/ plle2_adv_inst/CLKOUT1}
====================================================
Generated Clocks
====================================================
Generated Clock : clkfbout_clk_gen
Master Source : clk_gen_u/inst/plle2_adv_inst/CLKIN1
Master Clock : clk_in1
Multiply By : 1
Generated Sources : {clk_gen_u/inst/plle2_adv_inst/CLKFBOUT}
Generated Clock : clk_out1_clk_gen
Master Source : clk_gen_u/inst/plle2_adv_inst/CLKIN1
Master Clock : clk_in1
Edges : {1 2 3}
Edge Shifts : {0.000 5.000 10.000}
Generated Sources : {clk_gen_u/inst/plle2_adv_inst/CLKOUT0}
Generated Clock : clk_out2_clk_gen
Master Source : clk_gen_u/inst/plle2_adv_inst/CLKIN1
Master Clock : clk_in1
Edges : {1 2 3}
Edge Shifts : {0.000 45.000 90.000}
Generated Sources : {clk_gen_u/inst/plle2_adv_inst/CLKOUT1}
b.
图2
如图2中,衍生时钟CLKOUT1通过逻辑产生一个2分频的衍生时钟CLK_DIV2,CLKOUT1的约束已自动生成,对CLK_DIV2约束指令如下:
create_generated_clock -name CLK_DIV2 -source [get_pins clk_gen_u/clk_out1] -divide_by 2 [get_pins clk_25m_reg/Q]
生成的时钟报告如下:
====================================================
Generated Clocks
====================================================
Generated Clock : CLK_DIV2
Master Source : clk_gen_u/clk_out1
Master Clock : clk_out1_clk_gen
Divide By : 2
Generated Sources : {clk_25m_reg/Q}
Generated Clock : clkfbout_clk_gen
Master Source : clk_gen_u/inst/plle2_adv_inst/CLKIN1
Master Clock : clk_in1
Multiply By : 1
Generated Sources : {clk_gen_u/inst/plle2_adv_inst/CLKFBOUT}
Generated Clock : clk_out1_clk_gen
Master Source : clk_gen_u/inst/plle2_adv_inst/CLKIN1
Master Clock : clk_in1
Edges : {1 2 3}
Edge Shifts : {0.000 5.000 10.000}
Generated Sources : {clk_gen_u/inst/plle2_adv_inst/CLKOUT0}
Generated Clock : clk_out2_clk_gen
Master Source : clk_gen_u/inst/plle2_adv_inst/CLKIN1
Master Clock : clk_in1
Edges : {1 2 3}
Edge Shifts : {0.000 45.000 90.000}
Generated Sources : {clk_gen_u/inst/plle2_adv_inst/CLKOUT1}
3.3 Virtual Clocks
虚拟时钟是在FPGA设计不存在的时钟,但是为什么要引入呢?先看一下图3中结构,FPGA与板上的其它芯片间有数据交互,属于FPGA内部时序单元到输出端口的路径。芯片上的时钟并不是由FPGA提供,Vivado在进行这部分时序分析时并不知道芯片的时钟,因此需要定义一个虚拟时钟,然后约束输出端口的output delay。
图3
约束虚拟时钟的命令也是create_clock,但是其不需要指定-source,如下指令:
create_clock -period 100.000 -name SCLK -waveform {0.000 50.000}
时钟报告如下,定义的虚拟时钟SCLK属性为Virtual,无source。
report_clocks
INFO: [Timing 38-35] Done setting XDC timing constraints.
INFO: [Timing 38-2] Deriving generated clocks
*****************************************************************
* Report : Clocks
* Design : top
* Part : Device=7z020, Package=clg484, Speed=-1
* Version : Vivado v2013.1 Build 248050 by xbuild on Wed Mar 27 17:27:24 MDT 2013
* Date : Tue Dec 17 14:08:19 2013
***************************************************************************Attributes
P: Propagated
G: Generated
V: Virtual
I: Inverted
Clock Period Waveform Attributes Sources
clk_in1 10.00000 {0.00000 5.00000} P {GCLK}
CLK_DIV2 40.00000 {0.00000 20.00000} P,G {clk_25m_reg/Q}
SCLK 100.00000 {0.00000 50.00000} V {}
clkfbout_clk_gen 10.00000 {0.00000 5.00000} P,G {clk_gen_u/inst/
plle2_adv_inst/CLKFBOUT}
clk_out1_clk_gen 20.00000 {0.00000 10.00000} P,G {clk_gen_u/inst/
plle2_adv_inst/CLKOUT0}
clk_out2_clk_gen 100.00001 {0.00000 50.00000}
P,G {clk_gen_u/inst/plle2_adv_inst/CLKOUT1}
4 Timing Constraints in Vivado -- 4. Clock Groups
在第一节介绍过XDC与UCF的不同之处:Vivado会分析所有XDC约束时钟间的时序路径。通过set_clock_groups约束不同的时钟组(clock group),Vivado在时序分析时,当source clock和destination clock属于同一个时钟组时,才会分析此时序路径;而source clock和destination clock属于不同时钟组时,则会略过此时序路径的分析。下面讲解一下set_clock_groups约束:
4.1 Asynchronous Clock Groups
为了判别划分时钟组,将不同的时钟划分成以下两类:
a. Synchronous Clocks
当两个时钟间的相位是固定的,则可以称这两个时钟为同步时钟(synchronous clock)。一般同源,如由同一个MMCM or PLL产生的两个时钟可以称为同步时钟。因此可以将主时钟和与之对应的衍生时钟约束成同一个时钟组。
b. Asynchronous Clocks
无法判定两个时钟间相位时,则可以称这两个时钟为异步时钟(asynchronous clocks)。两个来自不同晶振的时钟,一定是异步时钟。通常情况下设计中不同的主时钟肯定是异步时钟,因此可以将这两个主时钟及其衍生时钟约束成不同的时钟组。
对于异步时钟,由于其两个时钟间相位不固定,时序分析的结果定然不确切,因此这部分的分析可以通过设置时钟组约束忽略,但是这并不意味着这部分的设计能工作正常;对于异步时钟间的设计,必须做跨时钟域处理,避免亚稳态的产生。
异步时钟组约束命令如下:
set_clock_groups-asynchronous-group [get_clocks {clk_Aclk_B}]
-group [get_clocks {clk_C}]-group …
如图1中结构,串行AD1和串行AD2接口都带有随路时钟SCLK1和SCLK2,SCLK1和SCLK2属于异步时钟;ADC串并转换后的数据需要经过跨时钟域处理(CDC),转到GCLK主时钟域,GCLK与ADC的时钟也属于异步时钟,因此约束命令如下:
set_clock_groups-asynchronous -group [get_clocks {SCLK1}]
-group [get_clocks {SCLK2}] -group [get_clocks {GCLK}]
图1
4.2 Exclusive Clock Groups
在有些设计中,可能需要不同的工作模式,对应需要不同的时钟输入,通过时钟选择模块选择需要的时钟,如BUFGMUX,BUFGCTRL or A LUT。但是这些输入的不同时钟间是互斥的,即一个模式只允许一个时钟输入,不同时钟间是没有时序关系,因此只需单独对每个时钟做时序分析即可,添加互斥时钟组可使Vivado进行时序分析时忽略互斥时钟组间的时序路径,约束命令如下:
set_clock_groups -logically_exclusive -group{clk_A} -group {clk_B}
或
set_clock_groups –physically_exclusive -group{clk_A} -group {clk_B}
如图2中结构,可将CLKMUX1,CLKMUX2约束成互斥时钟组,约束命令如下:
set_clock_groups - physically_exclusive -group [get_clocks {CLKMUX1}]
-group [get_clocks {CLKMUX2}]
图2
5 Timing Constraints in Vivado -- 5. Constraining Input Delay
Timing Constraints in Vivado系列博文已有了一定的进展,经过上两节的介绍,约束设计中的时钟后,Vivado已能完成基本的时序分析。
在第二节“Timing Basics”中提到时序路径分为以下四种:
1) FPGA内部时序单元间的路径
2) 输入端口到FPGA内部时序单元的路径
3) FPGA内部时序单元到输出端口的路径
4) 输入端口到输出端口的路径
其中1. FPGA内部时序单元间的路径中,时序分析所需要的时间参数:Tclk-D1, Tclk-Q, Tdata_path_delay, Tclk_D2, Tsetup, Thold已能确定,只要属于FPGA内部的时间参数,Vivado则会根据相应设计计算得到,因此4. 输入端口到输出端口的路径的时间参数也能确定。
其它两条路径都相应缺少FPGA外部的几个时间参数,这些参数都需要通过时序约束告知Vivado,然后Vivado才能精确地进行这些路径的时序分析。这一节先介绍2. 输入端口到FPGA内部时序单元的路径这条路径的约束。
在输入端口到FPGA内部时序单元的路径中,Input Delay这段路径是在FPGA外部,因此需要约束设置其时间参数,通过set_input_delay约束命令约束,具体如下:
set_input_delay –clock{clk} –max/-min input_delay_value [get_ports {DIN}]
另外根据source clock和destination clock,输入接口可分为以下两种情况:
5.1 System Synchronous Input
分析输入端口到FPGA内部时序单元的路径时,当source clock和destination clock来自同一个系统时钟时,称为系统同步输入(system synchronous input)。
如图1所示为系统同步输入,source clock是CLKA,destination clock是CLKB,其中CLKB通过输入端口引入FPGA内部(约束成主时钟),而CLKA引到了FPGA外部的板上芯片,并没有引入到FPGA内部,CLKB是采集输入端口的时钟,因此首先约束CLKB为主时钟,约束如下:
create_clock -name CLKB -period 10 -waveform {0 5} [get_ports {CLKB}]
图1
其中Tclkd_ext表示外部时钟源到外部芯片的延时;Tclkd_int表示外部时钟源到FPGA输入端口的延时;Tco表示外部芯片tCO时间;Tbd表示外部芯片输出端口到FPGA芯片的板上延时。
对应max_input_delay和min_input_delay,以上几个时间参数都有max和min值,约束如下:
set_input_delay -clockCLKB-max [Tclkd_ext_max + Tco_max + Tbd_max – Tclkd_int_min] [get_portsDIN]
set_input_delay -clockCLKB-min [Tclkd_ext_min + Tco_min + Tbd_min – Tclkd_int_max] [get_portsDIN]
5.2 Source Synchronous Input
分析输入端口到FPGA内部时序单元的路径时,当destination clock来自外部芯片,即与数据输入同源,称为源同步输入(source synchronous input)。
结构如图2所示,从板上芯片输入到FPGA除了有数据,还有一个随路时钟,是由板上芯片产生的。
图2
5.3 Input Delay Value:
约束Input Delay分max值和min值,参考图2中时间参数,其中Tcd表示外部芯片时钟输出到FPGA输入端口的延时;Tco表示外部芯片tCO时间;Tbd表示外部芯片输出端口到FPGA芯片的板上延时。Input delay的计算式如下:
max_input_delay = Tbd_max + Tco_max - Tcd_min
min_input_delay = Tbd_min + Tco_min - Tcd_max
5.4 Clock & Data:
源同步输入的约束相比于系统同步输入的复杂些,其根据时钟与数据的关系,可分为边缘对齐(Edge Aligned Clock&Data)和中心对齐(Center Aligned Clock&Data)两种:
1) Center Aligned
中心对齐是指时钟和数据到达后级时序单元时,时钟沿在数据中心,如图3所示。
在这种情况下可以直接使用时钟采集数据。
图3
约束如下:
create_clock -name CLKB -period clk_period [get_ports {CLKB}]
set_input_delay -clock[get_clocks CLKB] -max max_input_delay [get_ports indata]
set_input_delay -clock[get_clocks CLKB] -min min_input_delay [get_ports indata] -add_delay
2) Edge Aligned
边缘对齐是指时钟和数据到达后级时序单元时,时钟沿与数据变化沿重合,如图4所示。
图4
这种情况下显然不满足后级时序单元的Setup要求,因此时钟需要经过一定的移相才能去采集数据,通常采用MMCM模块实现移相,如图5所示。
图5
时钟约束如下:
create_clock -name CLKB -period clk_period [get_ports {CLKB}]
create_generated_clock -name CLKB_90 -source [get_clocks CLKB] –phase 90 [get_pins{MMCM|co[0]}]
set_input_delay -clock[get_clocks CLKB_90] -max max_input_delay [get_ports indata]
set_input_delay -clock[get_clocks CLKB_90] -min min_input_delay [get_ports indata] -add_delay
2.3 SDR & DDR:
源同步接口常用于高速数据传输,如DDR存储器、HyperTransport总线和SPI-4.2标准接口等。其中DDR指双倍速率数据采集(Double Data Rate),在时钟的上升沿和下降沿都传输数据实现双倍速率。
1) SDR(Single Data Rate)
单倍速率数据采集只在时钟的上升沿或者下降沿采集数据,如图6所示。
图6
Input约束只需针对时钟的上升沿或者下降沿进行,如:
set_input_delay -clock[get_clocks CLKB] -max max_input_delay [get_ports indata]
set_input_delay -clock[get_clocks CLKB] -min min_input_delay [get_ports indata] -add_delay
2) DDR(Double Data Rate)
双倍速率数据采集在时钟的上升沿和下降沿都采集数据,如图7所示。
图7
针对时钟的上升沿和下降沿都需要进行Input约束,如:
set_input_delay -clock[get_clocks CLKB] -max max_input_delay [get_ports indata]
set_input_delay -clock[get_clocks CLKB] -min min_input_delay [get_ports indata] -add_delay
set_input_delay -clock[get_clocks CLKB] -max max_input_delay [get_ports indata] -clock_fall -add_delay
set_input_delay -clock[get_clocks CLKB] -min min_input_delay [get_ports indata] -clock_fall -add_delay
5.5 Timing Check in Vivado
以上讲解了如何进行Input delay的约束,可能大家还不明白为什么需要约束input delay?那下面就讲解一下input delay 在时序分析中的作用:
在Vivado中时序分析分为setup check和hold check,其中引入了setup slack和hold slack来界定时序是否收敛。在《2. Timing Basics》中介绍过FPGA内部register_to_register路径setup slack和hold slack的计算方法,本文则介绍一下输入端口到FPGA内部时序单元的路径slack的计算方法,公式如下:
Setup check:
setup slack = data required time – data arrival time
其中:
data required time = destination clock edge time + destination clock path delay
- clock uncertainty
- setup time
data arrival time = source clock edge time + source clock path delay
+ max input delay
+ pin to register delay
为了确认公式的正确性,打开Vivado软件,新建了一个约束了input delay的工程,如下几图所示为中其中一条路径的setup check报告。
约束的时钟周期为40ns,max input delay为15ns
data arrival time= 15.322ns
data required time = 40.199ns
时序报告中slack计算方式与公式完全一致,因此可以得到setup slack = data required time – data arrival time= 40.199ns – 15.322ns = 24.846ns。
Hold check:
hold slack = data arrival time – data required time
其中
data required time = destination clock edge time + destination clock path delay
+ clock uncertainty
+ hold time
data arrival time = source edge time + source clock path delay
+ pin to register delay
+ min input delay
如下几图为Vivado软件分析得到的hold check时序报告:
约束的min input delay = 8ns
data arrival time= 6.474ns
data required time= 1.045ns
时序报告中slack计算方式与公式完全一致,因此可以得到hold slack = data arrival time – data required time= 6.474ns – 1.045ns = 5.429ns。
6 Timing Constraints in Vivado -- 6. Input Delay Constraints Instance I
这一节介绍input delay约束实例,加深一下对上节中理论的理解。
如图1所示系统,以太网PHY芯片与FPGA相连,分为三组接口:
RX接口:时钟RXCK和数据RXD;
TX接口:时钟TXCK和数据TXD;
MII管理接口:时钟MDC和数据MDIO。
图1
其中RX接口属于源同步输入接口,以下就以RX接口为例讲解一下约束input delay:
6.1 Clock Constraints:
首先约束时钟,如图2所示为PHY(DP83849ID)在100Mb/s模式下的时序图,时钟和数据为Center Aligned关系,因此时钟在FPGA中无需再移相,可直接使用RXCK采集数据,时钟约束如下:
create_clock –name RXCK –period 40 –waveform {0 20} [get_ports {RXCK}]
图2
6.1.1 Input Delay Value
根据上节中源同步输入计算Input Delay的公式:
max_input_delay = Tbd_max + Tco_max - Tcd_min
min_input_delay = Tbd_min + Tco_min - Tcd_max
Tbd为数据线RXD在板上的延时,也就是信号在电路板上的传播时间。查找了网上的一些资料:
“信号速度还与不同材料的介电常数相关,具体计算公式是 V=C/Er0.5 ,其中Er是信号线周围材料的相对介电常数。我们常见的PCB材料Fr4的介电常数在4.2-4.5左右,为了计算方便我们取4。带入公式可以算出,Fr4材料制作的PCB板上面信号的传输速度是光速的二分之一。光速大约等于12inch/ns,计算得出Fr4板上信号速度大约是6inch/ns。换算成延时,也就是166ps/inch。这就是我们经常说的PCB板上信号延时大约是166ps/inch。”
在此例中,通过PCB设计软件计算得到RXD[3:0]的走线长度,分别是LRXD[3]=426mil,LRXD[2]=451mil,LRXD[1]=502mil,LRXD[0]=406mil,因此可以计算得到:
Tbd_max = 502mil * 166ps/inch = 0.083332ns
Tbd_min = 406mil * 166ps/inch = 0.067396ns
Tcd为时钟线RXCK在板上的延时,走线长度LRXCK=399mil,因此可以计算得到:
Tcd_max=Tcd_min=399mil * 166ps/inch = 0.066234ns
Tco为RX接口clock_to_output时间,如图2中,等于T2.5.2时间参数,因此可得到:
Tco_max = 30ns
Tco_min = 10ns
综上:
max_input_delay = Tbd_max + Tco_max - Tcd_min = 0.083332ns + 30ns - 0.066234ns = 30.017098ns
min_input_delay = Tbd_min + Tco_min - Tcd_max = 0.067396ns + 10ns - 0.066234ns = 10.001162ns
6.1.2 Constraints
很显然,RX接口为SDR,时钟约束和input delay值的计算后,可以对input delay进行约束,命令如下:
set_input_delay -clock[get_clocks RXCK] -max 30.017098[get_ports {RXD[3] RXD[2] RXD[1] RXD[0]}]
set_input_delay -clock[get_clocks RXCK] -min 10.001162[get_ports {RXD[3] RXD[2] RXD[1] RXD[0]}]
在Vivado的GUI界面中也可以进行约束,设计经过综合实现后,打开编辑约束文件,如图3所示
图3
选择Set Input Delay,在右侧双击,可弹出Input Delay设置窗口,如图4所示
图4
在弹出的Input Delay窗口中设置参数,如图5,6所示,Input Delay约束完成。
图5
7 Timing Constraints in Vivado -- 7. Input Delay Constraints Instance II
在《6. Input Delay Constraints Instance I》中分享了一个实例,如图1所示,对RX接口进行了约束。另外MII管理接口,其中MDIO是双向数据接口,肯定需要input delay的约束,由于笔者开始不确定此接口属于系统同步输入还是源同步输入,没有做进一步介绍,那就在此篇博文深入分析一下。
图1
最初以为MII接口属于源同步输入,但是仔细查看后发现不对劲儿,时钟MDC并不是由PHY提供的,而是FPGA输出给PHY的,这与源同步接口的定义矛盾,源同步需要时钟和数据来自同一个源。因此只能划分到系统同步输入范畴了,仔细一想还是能说得通的,系统同步中只要求source clock和destination clock来自同一个时钟网络即可,不管是在FPGA外部还是内部,如图2所示,
图2
《5. Constraining Input Delay》系统同步输入的input delay value计算公式如下:
max input delay = Tclkd_ext_max + Tco_max + Tbd_max – Tclkd_int_min
min input delay = Tclkd_ext_min + Tco_min + Tbd_min – Tclkd_int_max
此例的情况,时钟源到FPGA输入端口的延时Tclkd_int等于0,时钟源到外部芯片的延时为TCD,因此得到变化后的公式如下:
max input delay = TCD_max + TCO_max + TBD_max
min input delay = TCD_min + TCO_min + TBD_min
各时间参数的计算如下:
TCD :时钟线MDC在板上的长度LMDC=489mil,TCD_max= TCD_min=489mil*166ps/inch= 0.081174ns
TBD:数据线MDIO在板上的长度LMDIO=634mil,TBD_max= TBD_min=634mil*166ps/inch= 0.105244ns
TCO: 参考PHY(DP83849ID)的手册,如图3所示,TCO等于时间参数T2.3.1,得到TCO_max=30ns,TCO_min=0ns。
图3
得到input delay值如下:
Max_input_delay = TCD_max + TCO_max + TBD_max
=0.081174ns+30ns+0.105244ns=30.186418ns
min input delay = TCD_min + TCO_min + TBD_min
=0.081174ns+0ns+0.105244ns=0.186418ns
综上,MII管理接口的约束如下:
create_clock –name MDC –period 400 –waveform {0 200} [get_ports {MDC}]
set_input_delay -clock[get_clocks MDC] -max 30.186418[get_ports {MDIO}]
set_input_delay -clock[get_clocks MDC] -min 0.186418[get_ports {MDIO}]
在Vivado中的约束如图4,5所示:
图4
图6
8 Timing Constraints in Vivado -- 8. Constraining Ouput Delay
FPGA内部时序单元到输出端口的路径也需要约束其output delay,如图1所示框图。
图1
约束output delay的命令是set_output_delay,具体的参数如下:
set_output_delay –clock reference_clock –min/-max delay_value
[get_ports {DOUT}] [-clock_fall] [-add_delay]
其中-clock表示输出端口的关联时钟;
-min/-max表示设置output delay的最小和最大值;
-clock_fall表示output delay是针对关联时钟的下降沿;
-add_delay表示对同一个输出端口约束不同的output delay值,一般是在如DDR需要约束两个时钟沿的output delay,或者输出端口后级连接了多个器件对应不同的时钟约束的情况下,需要加入此参数。
与输入接口约束类似,输出接口的约束也可分为以下两种情况:
8.1 System Synchronous Output
分析FPGA内部时序单元到输出端口的路径时,当source clock和destination clock来自同一个系统时钟时,称为系统同步输出(system synchronous output)。
此处需要引入虚拟时钟(virtual clock)的概念,在讲时钟约束的一节时有提到,当source clock or destination clock不在FPGA设计中时,则需要约束一个虚拟时钟。如图2所示为系统同步输出路径框图,source clock是CLKA,destination clock是CLKB,其中CLKA通过输入端口引入FPGA内部(约束成主时钟),而CLKB引到了FPGA外部的板上芯片,并没有引入到FPGA内部,因此需将CLKB约束成虚拟时钟,约束如下:
create_clock -name CLKA-period 10 -waveform {0 5} [get_ports {CLKA}]
create_clock -name CLKB-period 10 -waveform {0 5}
图2
其中Tcd_ext表示外部时钟源到外部芯片的延时;Tcd_int表示外部时钟源到FPGA时钟端口的延时;Tsetup表示外部芯片tsu时间;Thold表示外部芯片thd时间;Tbd表示FPGA输出端口到外部芯片的板上延时。
Output delay value的计算式如下:
max_output_delay = Tbd_max + Tsetup + Tcd_int_max - Tcd_ext_min
min_output_delay = Tbd_min – Thold + Tcd_int_min - Tcd_ext_max
相比于input delay value,上式相对于难理解些,那就推导一下,深入理解:
将此路径假想为FPGA内部register_to_register路径作分析,如图3所示,
图3
在《2. Timing Basics》节中,介绍了时序分析分为Setup Check和Hold Check:
(1) Setup Check
setup slack = (destination clock edge time - source edge time)
+ (destination clock path delay - source clock path delay)
- clock uncertainty
- setup time
- clock to output time
- data path delay
将图3中路径的时间参数代入可得:
setup slack = Tclk_period + (Tcd_ext – Tcd_int – Tcd_int_fpga) – Tclk_uncertainty – Tsetup – Tclk-Q– Tint_data_delay - Tbd
其中Tcd_ext,Tcd_int,Tsetup和Tbd都是FPGA外部的时间参数,需要通过约束告知vivado,上式整理一下可得:
setup slack = Tclk_period – Tcd_int_fpga – Tclk_uncertainty – Tclk-Q – Tint_data_delay
+ (Tcd_ext – Tcd_int) – Tsetup - Tbd = Tclk_period – Tcd_int_fpga – Tclk_uncertainty
– Tclk-Q – Tint_data_delay –Tmax_output_delay
Tmax_output_delay = Tsetup + Tbd_max + Tcd_int_max - Tcd_ext_min,与前文中max_output_delay的计算式相同。
(2) Hold Check
hold slack = (source clock edge time - destination edge time)
+(source clock path delay - destination clock path delay)
- clock uncertainty
- hold time
+ clock to output time
+ data path delay
= (Tcd_int + Tcd_int_fpga - Tcd_ext)
- Tclk_uncertainty
– Thold
+ Tclk-Q
+ Tint_data_delay + Tbd
其中Tcd_ext,Tcd_int,Thold和Tbd都是FPGA外部的时间参数,需要通过约束告知vivado,上式整理一下可得:
hold slack = Tcd_int_fpga - Tclk_uncertainty + Tclk-Q + Tint_data_delay + Tbd – Thold + Tcd_int - Tcd_ext
= Tcd_int_fpga - Tclk_uncertainty + Tclk-Q + Tint_data_delay + Tmin_output_delay
Tmin_output_delay = Tbd_min – Thold + Tcd_int_min - Tcd_ext_max,与前文中min_output_delay的计算式相同。
可以发现在setup check中使用max output delay,hold check使用min output delay,都是使slack的值较小的趋势,这样使FPGA内部的时序条件更严苛,如果在这种条件下时序收敛,就绝对能保证设计的稳定性。
经过上面的推导,回归系统同步输出主题,约束命令如下:
set_output_delay -clockCLKB -max max_output_delay [get_ports {DOUT}]
set_output_delay -clockCLKB -min min_output_delay [get_ports {DOUT}
8.2 Source Synchronous Output
分析FPGA内部时序单元到输出端口的路径时,输出到外部芯片的时钟与数据是同源的,称为源同步输出(source synchronous output)。
结构如图4所示,从FPGA输出到外部芯片除了有数据,还有一个随路时钟,由FPGA内部时钟模块产生的。
图4
参考图4中时间参数,其中Tcd表示时钟从FPGA输出到外部芯片输入端口的延时;Tsetup表示外部芯片tSU时间;Thold表示外部芯片tH时间;Tbd表示FPGA输出端口到外部芯片的板上延时。Output delay的计算式如下(推导与系统同步输出类似,不再累述):
max_output_delay = Tbd_max + Tsetup - Tcd_min
min_output_delay = Tbd_min – Thold - Tcd_max
源同步输出的output delay约束命令如下:
set_output_delay -clockCLKB -max max_output_delay [get_ports {DOUT}]
set_output_delay -clockCLKB -min min_output_delay [get_ports {DOUT}]
9 iming Constraints in Vivado -- 9. Output Delay Constraints Instance
本节讲解一下output delay的实例。依旧是Ethernet PHY和FPGA的接口,框图如图1所示,其中TX接口,MII管理接口输出方向需要output delay约束。
图1
(1) TX接口:
TX接口由时钟TXCK和数据TXD[3:0]组成,都是从FPGA输出,即时钟和数据同源,因此TX接口为源同步输出接口。
根据上节中output delay value的计算公式:
max_input_delay = Tbd_max + Tsetup - Tcd_min
min_input_delay = Tbd_min – Thold - Tcd_max
其中有4个时间参数:Tbd,Tcd,Tsetup和Thold,如图2所示。
图2
Tcd和Tbd分别是时钟TXCK和数据TXD[3:0]在板上的延时。首先通过PCB设计软件计算得到它们布线长度:LTXCK=784mil,LTXD[3]=663mil,LTXD[2]=680mil,LTXD[1]=852mil,LTXD[0]=901mil,因此计算得到:
Tcd_max= Tcd_min=784mil*166ps/inch= 0.130144n
Tbd_max=901mil*166ps/inch= 0.149566ns
Tbd_min=663mil*166ps/inch=0.110058ns
Tsetup和Thold是PHY(DP83849ID)芯片的时间参数,如图3所示,查询datasheet得到:
参考时间参数T2.4.2,Tsetup=10ns
参考时间参数T2.4.3,Thold=0ns
图3
综上可得到output delay value:
max_output_delay = Tbd_max + Tsetup - Tcd_min=0.149566ns
+ 10ns - 0.130144ns=10.019422ns
min_output_delay = Tbd_min – Thold - Tcd_max=0.110058ns
– 0ns - 0.130144ns=-0.020086ns
可能有些人会诧异,为什么min_output_delay的值会是负的?负的表示相对于输出是反方向的延时。
下面对TX接口的output delay进行约束:
create_clock -nameTXCK -period 40 -waveform {0 20} [get_ports {TXCK}]
create_clock -nameTXCK_PHY -period 40 -waveform {0 20}
set_output_delay –clock TXCK_PHY -max 10.019422 [get_ports {TXD[3] TXD[2] TXD[1] TXD[0]}]
set_output_delay –clock TXCK_PHY -min -0.020086ns [get_ports {TXD[3] TXD[2] TXD[1] TXD[0]}]
Vivado中约束如下图所示:
约束主时钟
约束虚拟时钟
约束min output delay
约束max output delay
(2) MII管理接口:
MII管理接口由时钟MDC和数据MDIO组成,其中MDIO为双向接口,因此需要对其进行input delay和output delay约束。在其output方向,MDC和MDIO都是从FPGA输出的,因此也是源同步输出接口。
时间参数的计算与TX接口类似,如图4所示
图4
其中MDC和MDIO在板上的布线长度分别为LMDC=924mil,LMDIO=587mil,可得:
Tcd_max= Tcd_min=924mil*166ps/inch= 0.153384ns
Tbd_max=Tbd_min=587mil*166ps/inch=0.097442ns
Tsetup和Thold的值参考datasheet,如图5所示,可得:
参考时间参数T2.3.2,Tsetup=10ns
参考时间参数T2.3.3,Thold=10ns
图5
综上可得到output delay value:
max_output_delay = Tbd_max + Tsetup - Tcd_min=0.153384ns + 10ns
- 0.097442ns=10.055942ns
min_output_delay = Tbd_min – Thold - Tcd_max=0.153384ns - 10ns - 0.097442ns=-9.944058ns
下面对MII管理接口的output delay进行约束:
create_clock -nameMDC -period 400 -waveform {0 200} [get_ports {MDC}]
create_clock -nameMDC_PHY -period 400 -waveform {0 200}
set_output_delay –clock MDC_PHY -max 10.055942 [get_ports {MDIO}]
set_output_delay –clock MDC_PHY -min -9.944058 [get_ports {MDIO}]
Vivado中约束如下图所示:
约束主时钟
约束虚拟时钟
约束max output delay
约束min output delay
10 Timing Constraints in Vivado -- 10. Multicycle Paths
之前分析的时序路径基本都是在单时钟周期内进行分析,source clock和destination clock是紧挨的两个时钟沿,可以说是最严格的情况。而一些情况下,可以放松这个分析条件,因此引入了多时钟周期路径(multicycle paths)的概念,如图1所示,data path中可能经过了N个时钟周期后,最终才采集数据。
图1
通过XDC命令约束多时钟周期路径,命令如下:
set_multicycle_path<path_multiplier> [-setup|-hold] [-start|-end] [-from <startpoints>] [-to<endpoints>] [-through <pins|cells|nets>]
其中<path_multiplier> [-setup|-hold] [-start|-end]的参数组合定义了多时钟周期路径的周期数。
path_multiplier默认值如下,可以发现默认值就是单时钟周期分析
• 1 for setup analysis
• 0 for hold analysis
[-setup|-hold]参数表示是针对setup分析还是hold分析,默认为-setup –end和-hold –start的组合,即约束setup分析时,对应destination clock需要移动;约束hold分析时,对应source clock需要移动。这样说可能不是很清晰,那就举例说明,以下都以source clock和destination clock是同一时钟的情况进行举例说明:
a. 默认情况,单时钟周期分析,每一个setup分析对应两种hold分析情况,选其中比较苛刻的情况做最终分析
set_multicycle_path1 -setup –end …
set_multicycle_path0 –hold –start …
b. 多时钟周期,相比于单时钟周期情况,只放宽setup分析需求,hold分析为默认情况
set_multicycle_path2 -setup –end …
c. 多时钟周期,相比于单时钟周期情况,只放宽hold分析需求,setup分析为默认情况
set_multicycle_path1 –hold –start …
d. 多时钟周期,改变setup和hold分析中对应时钟移动方式,setup分析中变为source clock移动1个时钟周期,hold分析中变为destination clock移动1个时钟周期
set_multicycle_path2 -setup –start …
set_multicycle_path1 –hold –end …
在vivado中进行multicycle path约束方法如下:
(1) 设计经过综合实现后,点击Edit Timing Constraints打开时序约束窗口
(2) 选择Set multicycle Path,在右侧双击打开多时钟约束窗口
(3) 设置参数
11 Timing Constraints in Vivado -- 11. Multicycle Paths Constraints Instance I
本节通过实例介绍一下多时钟周期路径(multicycle paths)的约束方法。
如图1中结构,主时钟fast_clk,时钟频率250MHz;时钟使能信号div_by_two,由主时钟2分频得到,作为寄存器的clock enable信号。
图1
HDL代码如下所示:
module top(
fast_clk,
din_a,
din_b,
din_x,
din_y,
ab_out,
xy_out
);
// PORT /
input fast_clk;
input [7:0] din_a;
input [7:0] din_b;
input [7:0] din_x;
input [7:0] din_y;
output reg [15:0] ab_out;
output reg [15:0] xy_out;
// ARCHITECTURE /
// Clock Enable
reg div_by_two;
always@(posedge fast_clk)
div_by_two<=~div_by_two;
// Input Registers
reg [7:0] din_a_rg;
reg [7:0] din_b_rg;
reg [7:0] din_x_rg;
reg [7:0] din_y_rg;
always@(posedge fast_clk) begin
if(div_by_two) begin
din_a_rg <= din_a;
din_b_rg <= din_b;
din_x_rg <= din_x;
din_y_rg <= din_y;
end
end
// Multiplexer
wire [7:0] mult_a;
wire [7:0] mult_b;
assign mult_a = div_by_two ? din_a : din_x;
assign mult_b = div_by_two ? din_b : din_y;
// Multiplier
wire [15:0] mult_rlt;
assign mult_rlt = mult_a * mult_b;
// Ouptut Select
always@(posedge fast_clk) begin
if(div_by_two)
xy_out <= mult_rlt;
else
ab_out <= mult_rlt;
end
endmodule
时序图如图2所示,其中div_by_two_reg --> din_*_reg[*]和div_by_two_reg --> **_out_reg[*]路径都需要2个clock cycle,所有的多时钟周期路径如下表所示:
Source Register Destination Register Set-Up Relationship Hold Relationship
div_by_two_reg din_a_reg[*],din_b_reg[*] 2x(latch edge time) 1x (latch edge time)
div_by_two_reg ab_out_reg[*],xy_out_reg[*] 2x (latch edge time) 1x (latch edge time)
图2
综合后,首先约束主时钟,如图3所示,此时时序还未收敛,时序报告如图4所示,可以发现关键路径都是需要多时钟周期约束的路径。
图3
图4
然后约束多时钟周期路径,约束命令如下,如图5所示;此时时序也收敛,时序报告如图6所示。
set_multicycle_path -setup -from[get_cells div_by_two_reg]
-to [get_cells {ab_out_reg[*] din_a_IBUF[*]_inst
din_b_IBUF[*]_inst din_x_IBUF[*]_inst din_y_IBUF[*]_inst xy_out_reg[*]}] 2
set_multicycle_path -hold -from[get_cells div_by_two_reg]
-to [get_cells {ab_out_reg[*] din_a_IBUF[*]_inst
din_b_IBUF[*]_inst din_x_IBUF[*]_inst din_y_IBUF[*]_inst xy_out_reg[*]}] 1
图5
12 Timing Constraints in Vivado -- 12. Multicycle Paths Constraints Instance II
本节继续通过一个实例介绍多时钟周期路径(multicycle paths)的约束方法。
如图1所示,算法实现一个限幅器,数据输入DIN,限幅绝对值输入L,数据输出DOUT,输入与输出关系如下式:
图1
显然,在LMT1 Register和LMT2 Register中需要实现48-bit与48-bit的比较器逻辑,而250MHz的时钟频率要求过于严苛,实现代码如下:
module LIMIT
(
CLK,
DIN,
L,
DOUT
);
// Parameter
parameter D_WDH = 48;
parameter L_WDH = 48
// PORT
input CLK;
input [D_WDH-1:0] DIN;
input [L_WDH-1:0] L;
output [D_WDH-1:0] DOUT;
// ARCHITECTURE
reg [D_WDH-1:0] LMT_RG1;
reg [L_WDH-1:0] L_N;
always@(posedge CLK) begin
LMT_RG1 <= DIN;
L_N <= -L;
end
wire [D_WDH-1:0] LMT_P;
assign LMT_P = LMT_RG1[D_WDH-1:D_WDH-L_WDH] > L ? {L,{D_WDH-L_WDH{1'b0}}} : LMT_RG1;
wire [D_WDH-1:0] LMT_N;
assign LMT_N = LMT_RG1[D_WDH-1:D_WDH-L_WDH] < L_N ? {L_N,{D_WDH-L_WDH{1'b0}}} : LMT_RG1;
reg [D_WDH-1:0] LMT_RG2;
always@(posedge CLK) begin
if(LMT_RG1[D_WDH-1])
LMT_RG2 <= LMT_N;
else
LMT_RG2 <= LMT_P;
end
assign DOUT = LMT_RG2;
endmodule
设计经过综合后,然后进行约束,首先是全局时钟约束(250MHz):
create_clock -name{MCLK} -period 4 -waveform { 0.000 2 } [get_ports {clk}]
由于笔者是单独针对LIMIT模块建立的工程,并没有实际的IO约束,让vivado自动分配位置。
芯片选择zynq xc7z020,由于逻辑量较少,经过布局布线后被分配到了右下角位置处,如图2所示。
图2
果不其然,时序报告见红了,如图3
但是庆幸的是,系统并不要求这个限幅操作在单时钟周期内完成,因此有优化的余地。对于这种因逻辑层数过长导致的时序问题,通常的解决办法是加入寄存器分割路径,而本节介绍另一种方法,相信大家也猜出来了,就是通过多时钟周期路径约束解决,如图4所示:
图4
在此例中对LMT1 Register-->LMT2 Register的路径进行多时钟周期路径约束,约束命令如下:
set_multicycle_path -setup -end -from{ LMT_RG1[*]} -to { LMT_RG2[*]} 2
set_multicycle_path -hold -end -from{ LMT_RG1[*]} -to { LMT_RG2[*]} 1
经过综合实现后,时序报告如图5所示,slack余量很充足;图6显示通过多时钟周期路径约束设置了时序例外,放宽了时序分析要求(2 clock cycle = 8ns)。
图5
图6
采用多时钟周期路径约束办法的好处就是:无需修改verilog HDL源代码,只需简单添加几条时序约束命令即可,效率大大滴提升。
13 Timing Constraints in Vivado -- 13. False Paths
在FPGA设计中,并不是所有的路径都需要做时序分析,称之为假路径(false path),比如有些路径在正常工作时并没有实现具体的逻辑功能,或者一些测试阶段使用的逻辑;有些是不需要做时序分析,如跨时钟域路径。
可以通过添加false_path约束,告知vivado在时序分析时忽略这些路径,这样带来的好处有:
a减少编译时间:vivado不需要对这些路径进行时序分析,也不需要为了优化这些路径而在P&R中花过多的时间;
b增加结果可靠性:约束false path并不是让vivado作弊,而是在实际工作中确实不需要考虑这些路径。如果不约束,反而会使vivado偏离了正规,在努力优化false path时可能忽略了true path的时序问题。
set_false_path约束命令如下,可以约束两个节点(node_list)间的路径,也可以约束两个时钟间的所有路径:
set_false_path[-setup] [-hold] [-from <node_list>] [-to <node_list/clock>] [-through<node_list/clock>]
注:false path约束和multicycle path约束同属于时序例外(timing exception)约束的范畴,两者的区别是:false path约束彻底取消对该路径的时序分析,而multicycle path约束只是放松时序分析的要求,vivado依然会对multicycle path进行时序分析和优化。
set_false_path可以直接对两节点进行约束,如图1所示路径,由于两个数据选择器由同一个信号控制,数据流分别连接了两个数据选择器的a0端和a1端,因此不可能有数据通过,可对REGA和REGB间的路径做false path约束,命令如下:
set_false_path -from {REGA} -to {REGB}
图1
另外set_false_path也可以直接对两时钟进行约束,表示将所有两个时钟间的路径都设置成false path,如下所示:
set_false_path-from [get_clocks CLKA] -to [get_clocks CLKB]
之前关于时钟约束的博文中有介绍,对两异步时钟需要设置不同的时钟组,可以通过set_clock_group约束,如下命令所示
set_clock_groups -group CLKA -group CLKB
set_false_path约束异步时钟和set_clock_group约束能达到相同的功能,不同的是set_clock_group同时约束了CLKA-->CLKB和CLKB-->CLKA的路径;而set_false_path是单向的,如上例中只约束了CLKA-->CLKB的路径,如下两条命令就与set_clock_group等价了:
set_false_path-from [get_clocks CLKA] -to [get_clocks CLKB]
set_false_path-from [get_clocks CLKB] -to [get_clocks CLKA]
14 Timing Constraints in Vivado -- 14. XDC编辑器的使用
本节介绍一下Vivado中XDC编辑器的使用方法。
(1) 代码编辑器输入:
首先最简单的方法,在新建或者添加*.xdc文件后,双击即可打开,然后在代码边界窗口中直接编写XDC约束命令,如图1所示:
图1
(2) Timing Constraints Editor输入:
XDC约束可以在synthesis和implementation过程中添加,如图2所示,打开synthesis和implementation后的设计,其中都有Edit Timing Constraints选项。
图2
打开Timing Constraints Editor界面,分为三个区域:1 所有约束命令列表(左上);2 约束命令编辑窗口(右上);3 所有已添加约束命令(下)。
图3
以create_clock命令为例,双击左上区域的命令,则会弹出约束时钟的窗口,另外可以直接在右上区域修改编辑约束命令中的参数,如图4所示,都是在GUI界面中添加约束命令。
图4
(3) Tcl Console输入
XDC约束命令都是基于Tcl脚本语言的语法,因此可以在Vivado的Tcl Console中直接添加XDC命令,如图5所示,在输入命令时,会自动弹出所有符合当前输入的命令列表,如图中只输入了get_,自动弹出了所有“get_*”格式的命令,既可以作为参考可以直接点击选择;当弹出列表只有一条符合命令时,可以按Tab自动补全。
图5
在Tcl Console输入的XDC命令自动添加到Timing Constraints Editor中,可以在其中进行命令保存工作。
在synthesis和implementation过程中,如XDC命令有错误,则会弹出critical messages,如图6所示。
图6
如果错误的XDC命令比较多,通过write_xdc命令将这些错误命令写入另外一个*.xdc文件中,如图7所示,此例中有1条错误命令,写入到invalid.xdc文件中。
图7
15 跨时钟域处理
时钟对于FPGA就像我们的心脏,时刻控制着“跳动”的频率以及“血液”的流速;时钟域好比通过心脏的血液血型,不同血型的血液会产生排斥作用。在设计中建议时钟越少越好,好比于人有两个甚至更多的心脏,其内脏工作将会多么混乱。但是某些情况下多时钟又不可避免,比如从FPGA外部输入的数据,其自带有个随路时钟,数据终归要在FPGA内部时钟域下处理,这来自外部的“血液”如何处理才能与内部的“血液”融合呢?配对及转换工作则是必不可少的,这就引入本节的主题:跨时钟域处理(Clock Domain Crossing):
跨时钟域处理需要两方面的工作:1. 设计者处理;2. FPGA工具(Vivado)处理。
15.1 设计者处理
首先讲解一下如果不进行跨时钟域处理,会出现什么问题呢?如图1所示路径,QA属于CLKA时钟域的数据输出,另一个时钟CLKB去捕获节点REG A的输出QA,假定CLKA与CLKB是异步时钟,它们之间的相位并不固定,因此捕获过程中可能会出现建立冲突(setup violation)和保持冲突(hold violation),如图2所示,左右分别为发生建立冲突和保持冲突的情况。
图1
图2
当冲突出现时(我感觉整个人都不好了),会发生什么事情呢?在发生建立冲突或者保持冲突,捕获节点(REG B)会处于一个不定的状态,正常的状态是高电平或者低电平,而此时的状态停留在高电平和低电平的中间,无效的电平X,称这个状态为亚稳态。如图3所示,捕获节点输出保持在亚稳态,可能在整个时钟周期内都保持在亚稳态,由于不正确的状态,其后连接的逻辑在功能实现上就会出现问题,比如一个判断信号上升沿的逻辑,通常判断D == HIGH && D_PREV == LOW(D为信号当前电平状态,D_PREV为信号上个时钟的电平状态)是否成立,而发生亚稳态时则D_PREV == X,这个上升沿将会错过。因此,加入跨时钟域处理设计是必须的。
图3
对于单比特信号的跨时钟域处理,常用的方法是“打两拍”,即在捕获时钟域中加入两个寄存器进行时钟转换,如图4所示,加入REG B1和REG B2,虽然REG B1处于亚稳态状态,但是REG B2的输出QB2能稳定在正常的电平上,由于REG B1和REG B2之间没有多余的逻辑,REG B1能有充裕的时间稳定状态,此情况下REG B2能完美地隐藏REG B1的亚稳态。在捕获时钟的频率比较高的情况下,如果一个REG B2还未能隐藏亚稳态,拍数也可以增加三个或者更多,当然一般情况下,两拍足矣。
图4
对于多比特总线数据的跨时钟域处理,能否也使用“打两拍”的方法呢?答案见图5,虽然REG B2的输出是稳定的,稳定在哪一个电平是不确定的,不过会在当前时钟或者下一个时钟输出正确电平,即偏差在一个时钟周期,也就是说不能保证所有比特位的状态一致,也是这个原因,导致传输多比特总线数据时各比特位不同步,常用的解决方法是加入FIFO隔离,如图6所示,FIFO能有效地隔离两个时钟域,避免亚稳态的发生。
图5
图6
(3) FPGA工具(Vivado)处理
Vivado采用XDC对时序进行约束,默认情况下,会分析所有时钟的路径,当然也包括跨时钟域的路径。
设计经过综合实现后,在Implementation中点击Report Clock Interaction(见图7),得到设计中所有时钟的交互情况,如图8所示,共有两个时钟:CLK_REG和CLK_USR,红色区域表示Timed(unsafe),说明两个时钟间有时序路径。
图7
图8
可以发现在图8底部时序分析的结果,有红色报警说明有路径时序未收敛,打开时序分析报告(见图9),source clock是CLK_REG,destination clock是CLK_USR,说明是一条跨时钟域路径,其中Requirement只有0.001ns,显然对跨时钟域路径的分析不合理,因此通常在保证设计者处理完成后,添加时序约束,是Vivado忽略对跨时钟域路径进行时序分析。
图9
可以通过设置时钟组(clock group)或者设置假路径(false path)处理跨时钟域路径。如图10所示,在clock interaction中红色区域右击,选择Set Clock Groups或者Set False Path,
图10
Set Clock Group和Set False Path的区别是,前者设置了双向(CLKA-TO-CLKB和CLKB-TO-CLKA)的路径,而后者只设置单向(CLKA-TO-CLKB或者CLKB-TO-CLKA)的路径,此例中因为只有单向区域有路径交互,因此使用Set False Path即可。
图11
添加完约束后,时序报告中Inter-Clock Paths没显示有路径,并且没有未收敛的时序路径,如图12所示,Clock Interaction中原先红色区域变成了蓝色(User Ignored Paths),可以确认约束生效。