FPGA之道(80)静态时序分析(六)常用时序约束介绍(基于ISE的UCF文件语法)

文章目录

  • 前言
  • 常用时序约束介绍
    • 时序环境约束
    • 分组时序约束
      • TNM
      • TNM_NET
      • TIMEGRP
    • 常用时序约束
      • 周期约束
        • 输入时钟周期约束
        • 内部时钟周期约束
        • 关联时钟周期约束
        • 差分时钟周期约束
      • 输入约束
        • SDR输入约束
        • DDR输入约束
        • MDR输入约束
        • 差分输入约束
      • 组间约束
        • 焊盘到焊盘路径约束
        • 多周期路径约束
        • 跨时钟域路径约束
        • 跨时钟域忽略约束
        • 路径中间点约束
      • 输出约束
        • 直接同步输出约束
        • 间接同步输出约束
        • 差分输出约束

前言

本文摘自《FPGA之道》。

常用时序约束介绍

时序约束是我们对FPGA设计的要求和期望,例如,我们希望FPGA设计可以工作在多快的时钟频率下等等。因此,在时序分析工具开始对我们的FPGA设计进行时序分析前,我们必须为其提供相关的时序约束信息。在【时序分析的原理】章节中,我们介绍了很多原理性的东西,而在本章节,我们将为大家介绍在解决具体问题时该如何向时序分析工具表述清楚我们的意图,从而启动其强大的逻辑锥求解功能来得出我们所关心的时序分析报告。
当然了,时序分析工具的种类有很多,虽然它们所支持的时序约束语法不尽相同,但主体思想都是一致的。 因此,本章节就以Xilinx集成开发环境ISE中自带的时序分析工具为例,来为大家介绍一些UCF文件中常用的时序约束。(注意,时序分析环节仅仅是用来对FPGA设计的实现进行评估并给出相应的结果报告,它并不会对FPGA设计进行改变。但如果我们在使用诸如ISE、Quarters这样的集成开发环境时,如果在映射环节还没开始前就添加一些时序约束信息,则这些编译器每完成一部分布局布线工作,便会调用相应时序分析工具进行一次时序分析,如果发现分析结果不符合要求,则会返回重来。像这样,编译器经过多次反复努力,力求达到时序约束中的要求,从而给我们一种“时序分析改变FPGA实现”的错觉。因此,如果你想利用ISE做纯粹的时序分析,请使用PCF文件,当然语法也会略有不同。)

时序环境约束

在【本篇->基本概念介绍->影响延迟的因素->三种工况】中,我们介绍过环境因素对时序分析的影响。在默认的情况下,ISE自带的时序分析工具通常会采用最大工况来进行分析,不过我们也可以通过时序环境约束来定义自己想要的环境因素,例如:
TEMPERATURE = 85 C;
VOLTAGE = 0.95 V;

分组时序约束

在介绍描述具体情况的时序约束之前,让我们先来简单了解一下ISE所提供的一些基本分组时序约束语法,因为即使你的FPGA设计得再简单,也总不可能一个元素接一个元素的去添加时序约束吧?如果能够先建立分组,将有共性的元素划分到一起,然后再统一添加时序约束,将会极大的简化我们的工作量。

TNM

TNM是最基本的分组约束语法,其语法定义如下:

{NET|INST|PIN} "net_or_pin_or_inst_name" TNM = [predefined_group] identifier;

可见,TNM的定义起始关键字可以有三种——NET(网络)、INST(实例)、PIN(端口),其中,NET关键字用来指明网络分组,该分组约束会自动包含"net_or_pin_or_inst_name"名称中指定的那个网络名下0000000000000000000000000000000000000000000000游所连接的所有元素;INST关键字用来指明一个实例,为后续该分组的搜索限制了一个范围;PIN指的是端口,指明具体某个原语的管脚。
predefined_group是一个可选的参数,不写明的时候,该分组包含所有可包含的元素;若注明,则该分组只包含[predefined_group]类的元素。针对ISE软件来说,预先定义好的分组大概有以下这些:

FFS:触发器组;
RAMs:存储器组;
LATCHES:锁存器组;
PADS:焊盘组;
CPUS:处理器组;
HSIOS:高速IO组;
MULTS:乘法器组。

最后identifier指明了该分组的名称,以供后续语法在调用该分组时使用。

TNM_NET

TNM_NET也是一个基本的分组约束语法,其语法定义如下:

{NET|INST} "net_name" TNM_NET = [predefined_group] identifier;

TNM_NET分组定义语法几乎与TNM是一样的,除了两个区别:
1、TNM_NET只能根据网络来定义分组;
2、TNM_NET指明的网络名在选择分组成员时,可以穿过IBUF、BUFG这样的原语去往下游扩散,而TNM则不行。因此,通常用TNM_NET来为FPGA芯片的焊盘部分指定分组。

TIMEGRP

TIMEGRP是一个针对分组进行操作的语法关键字,我们可以利用该关键字对分组求并、求差或者指定时钟边沿,例如:
TIMEGRP “ffs123” = “ffs1” “ffs2” “ffs3”; #合并三个分组为一个分组
TIMEGRP “G1D2” = “G1” EXCEPT “G2”; #定义一个包含所有属于"G1"但不属于"G2"元素的分组
TIMEGRP “group1”=RISING FFS; #基于FFS分组定义一个敏感时钟上升沿的分组
TIMEGRP “group2”=FALLING FFS; #基于FFS分组定义一个敏感时钟下降沿的分组
注意,对ISE的时序分析工具来说,在时序约束信息中,对分组名或信号名等名称使不使用双引号都是ok的。另外,UCF文件中的注释符号为“#”。

常用时序约束

对于FPGA设计来说,常用的时序约束基本上可以被划分为四种类型,分别介绍如下:

周期约束

周期约束又叫时钟约束,主要用于给时钟信号指明相关约束,使用关键字PERIOD,其基本语法定义如下:

TIMESPEC "TS_name" = PERIOD "TNM_name" <period> {HIGH|LOW} [high_or_low_time] [INPUT_JITTER value];

其中,
TIMESPEC "TS_name"为该周期约束定义了一个标示符,可供其他地方调用。
"TNM_name"指明该周期约束所覆盖的时序分组。
指明了该周期约束的时钟周期数值。
{HIGH|LOW}指明了对应时钟信号在0时刻是以高电平(或上升沿)开始还是以低电平(或下降沿)开始的。
[high_or_low_time]是针对{HIGH|LOW}来说的,指明时钟信号起始电平的持续时间,类似占空比的概念,因此也可以用百分数来表示,意思是起始电平占整个周期的比例。
[INPUT_JITTER value]则指明了对应时钟信号存在一定的输入jitter。

输入时钟周期约束

要对一个被输入时钟所驱动时钟域进行时序分析,需要先定义一个需要被分析的分组,然后再使用TIMESPEC语法指定并命名一个周期约束,例如:
NET “clk50MHz” TNM_NET = “clkIn”;
TIMESPEC “TS_clkIn” = PERIOD “clkIn” 20.0 ns HIGH 50%;
上例中的第一句分组约束,将所有clk50MHz端口网络所连接的元素全部加入到clkIn分组中。而第二句话则指明该时钟域的时钟信息,表示定义了一个名为TS_clkIn的周期约束,其内容为针对clkIN时序分组,添加了一个周期为20ns、起始电平为高电平、占空比为50%的周期约束。
当然了,除了使用百分比来指电平占空比参数外,还可直接标明电平持续时间,例如,上例第二句话又可改写为:
TIMESPEC “TS_clkIn” = PERIOD “clkIn” 20.0 ns HIGH 10.0 ns;
若该时钟域的时钟信号还存在着2ns的jitter,则上例第二句话又可改写为:
TIMESPEC “TS_clkIn” = PERIOD “clkIn” 20 ns HIGH 50% INPUT_JITTER 2 ns;

内部时钟周期约束

内部时钟周期约束和输入时钟周期约束没有什么本质的不同,都是将周期约束加入到对应的时钟网络上,不过有一点需要特别注意:
输入时钟周期约束针对的是输入时钟信号,该时钟信号是通过FPGA的一个输入管脚引入FPGA内部的,如果我们将该管脚和FPGA顶层实体的输入端口clk绑定,那么无论是综合前后、布局布线前后,使用clk这个名称都能找到对应的时钟网络,因为关于这个时钟输入端口实在是没有什么好优化和改名的。
但是,若你要约束一个内部的时钟信号,若该信号在HDL文件中的名称为clk25MHz,若你定义了如下分组约束:
NET “clk25MHz” TNM_NET = “innerClk”;
则时序分析工具在进行分析的时候几乎会百分之百的报告说找不到这个名称叫做clk25MHz的网络,因为它几乎肯定会被优化或改名掉。针对此类情况,通常有三种解决方案:
1、使用ISE自带时序分析工具的时序约束创建工具创建该时钟的约束。通常,ISE会分析出其内部具有哪几个时钟信号,并会给出每一个时钟信号的源头网络名称,你可以据此名称推测出该网络是不是你HDL代码中类似clk25MHz名称对应的时钟网络,然后使用该网络名称创建分组约束。
2、在综合的时候使用综合约束中的keep语法,让clk25MHz这个网络名称不被优化掉。
3、查看综合、转换环节后的FPGA设计网表文件,找到clk25MHz可能对应的那个网络名称,然后使用该网络名称创建分组约束。(阅读网表的过程可能会很痛苦!)
当然了,对于一个验证团队来说,对于内部时钟来说,要想添加纯时序分析所使用的约束的话,恐怕只有采用方案3了。

关联时钟周期约束

关联时钟周期约束主要用来应付两种情况:一、如果两个时钟域之间有信息传递,且我们想要对此进行时序分析;二、一个时钟信号本身就是由另一个时钟信号生成的,两者之间具有很强的相关性。
例如,对于一个DCM模块来说,其输入来自一个叫做clk50MHz的管脚,我们对该时钟网络进行周期约束如下:
NET “clk50MHz” TNM_NET = “clkIn”;
TIMESPEC “TS_clkIn” = PERIOD " clkIn" 20 ns HIGH 50%;
如果它有一个同相2倍频的输出时钟,对应网络名称叫做clk2x,则对此输出时钟所驱动的网络,我们可以定义时序约束如下:
NET “clk2x” TNM_NET = DCM2xOut;
TIMESPEC TS_DCM2xOut = PERIOD “DCM2xOut” TS_clkIn / 2 HIGH 50%;
而对于该DCM的相移180度的2倍频输出时钟,若其对应网络名称叫做clk2x180,则对此输出时钟所驱动的网络,我们可以定义时序约束如下:
NET " clk2x180" TNM_NET = DCM2x180Out;
TIMESPEC TS_DCM2x180Out = PERIOD “DCM2x180Out” TS_clkIn / 2 PHASE 5 ns HIGH 50%;

差分时钟周期约束

如果输入时钟信号是差分的,那么你只需要给差分中的一个端口加上周期约束即可。为了好理解起见,你应该对差分的p端网络添加一个和差分时钟相同的周期约束。

输入约束

输入约束主要针对同步输入接口,亦或是针对虚拟出来的同步输入接口,通过使用“OFFSET = IN”关键字,来描述输入数据与时钟之间的关系。其基本语法定义如下:

[{TIMEGRP|NET} "iobgroup_or_padnet_name"] OFFSET = IN <offset_time> [units] [VALID <datavalid time>] {BEFORE|AFTER} "clk_name" [TIMEGRP "group_name"] {HIGH|LOW};

其中,
[{TIMEGRP|NET} “iobgroup_or_padnet_name”]可以为该输入约束指明一个网络或者一个分组(注意,这里的网络必须是连接到pad的网络,分组也必须是IO block相关的分组),若省略不写,则该约束的作用范围是全局的(应用于所有跟时钟"clk_name"相关的输入端口)。
是一个相对于所依赖时钟初始边沿的数据到来偏移量。当然了,具体该时钟的初始边沿是上升沿还是下降沿,则要追朔到该时钟相关的周期约束上,通过该周期约束的使用的是HIGH、LOW关键字中的哪一个来判断。
[VALID ]给出了数据信号的稳定周期,即在的基础上,保持稳定时间为。
{BEFORE|AFTER}则指出了该条约束中描述的有效数据是应该被当前时钟事件所采集还是应该被后续时钟事件所采集的。如果使用了BEFORE关键字,则表示数据有效开始是以要采集它的时钟事件为基础,给出一个提前量的;如果使用了AFTER关键字,则表示数据有效开始是以前一个时钟事件为基础,给出一个滞后量的。当然了,本身也可以是负值,而具体使用哪一个关键字,完全看个人的描述习惯,它们之间没有任何本质的不同。
"clk_name"指明了该输入约束是相对于哪一个时钟事件的初始边沿来说的。
[TIMEGRP “group_name”]为该约束指明了一个需要分析的内部分组,省略不写则表示所有跟当前时钟采集有关的元素。
{HIGH|LOW}则用来改写"clk_name"的初始边沿的,它可以改变周期约束对"clk_name"相关初始边沿的设定,HIGH、LOW分别表示的是将时钟上升沿、下降沿设定为0时刻的初始边沿。

SDR输入约束

SDR的概念请回顾【程序设计篇->编程思路->关于外接接口的编程思路->按时钟特性分类->同步接口->SDR】小节。
既然是同步接口,那么我们必须首先为同步时钟定义一个周期约束,例如:
NET “clk” TNM_NET = clk50MHz;
TIMESPEC TS_clk = PERIOD “clk50MHz” 20 ns HIGH 50%;
那么,下面就可以基于该时钟来使用“OFFSET = IN”语法表明该SDR接口在输入的时候数据与时钟之间的关系。例如:
OFFSET = IN 10 ns VALID 20 ns BEFORE clk;
由于本条语句没有指名具体的输入端口,因此它的作用是全局的,即所有跟clk时钟采集相关的输入端口。但是,若不同的数据端口与时钟之间的关系有所不同的话,则需要单独为每一个输入端口指明输入约束,例如:
NET “dIn<0>” OFFSET = IN 20 ns VALID 20 ns BEFORE “clk”;
NET “dIn<1>” OFFSET = IN 10 ns VALID 20 ns BEFORE “clk”;
如果有多个输入端口和时钟信号具有同样的关系,则可使用分组的形式去定义输入约束,例如:
NET “dIn<0>” TNM = dInG;
NET “dIn<1>” TNM = dInG;
TIMEGRP “dInG” OFFSET = IN 20 ns VALID 20 ns BEFORE “clk”;

DDR输入约束

DDR的概念请回顾【程序设计篇->编程思路->关于外接接口的编程思路->按时钟特性分类->同步接口->DDR】小节。
类似的,既然是同步接口,那么我们必须首先为同步时钟定义一个周期约束,例如:
NET “clk” TNM_NET = clk50MHz;
TIMESPEC TS_clk = PERIOD “clk50MHz” 20 ns HIGH 50%;

那么,下面就是一种基于该时钟来使用“OFFSET = IN”语法表明该DDR接口在输入的时候数据与时钟之间关系的方法,例如:
OFFSET = IN 5 ns VALID 10 ns BEFORE “clk” RISING;
OFFSET = IN 5 ns VALID 10 ns BEFORE “clk” FALLING;
这两行语法说明两个时钟边沿都分别对应其所需要采样数据的中间。注意,上例中多了两个关键字RISING和FALLING,它们不光可以用来指明offset time为5ns,到底是相对于时钟网络clk的上升沿来说还是下降沿来说,更重要的是,它们可以指明,该条输入约束的作用范围——RISING代表分析所有在上升沿被采样的输入分组,FALLING代表分析所有在下降沿被采样的输入分组。正因为如此,虽然这两条语句针对的输入端口都是一样的,但是它们并没有被互相覆盖。例如,如果我们想当然的将RISING、FALLING关键字替换为HIGH、LOW关键字如下:
OFFSET = IN 5 ns VALID 10 ns BEFORE “clk” HIGH; #Wrong for DDR
OFFSET = IN 5 ns VALID 10 ns BEFORE “clk” LOW; #Wrong for DDR
则,由于上述两条语句针对的都是一样的分组(所有跟clk相关的输入元素),因此谁写在前面谁就会被后面的语句覆盖掉。
也正是因为RISING和FALLING这样的一个分组特性,所以如果在SDR接口中,内部逻辑本身是上升沿敏感的,但如果你用FALLING来指明数据、时钟之间的位置关系,时序分析工具将会告诉你0条路径、0个端口等等被分析。此时,如果你执意要以下降沿来作为参考边沿的话,请使用LOW关键字。

为DDR接口添加时序约束的另一种方法是使用内部分组,例如,为了实现与第一种方法相同的约束,可以先定义两个分组分别对应上升沿敏感的元素和下降沿敏感的元素,然后分别为其指明输入约束,描述如下:
TIMEGRP “ClkIn_Rising” = RISING “clk50MHz”;
TIMEGRP “ClkIn_Falling” = FALLING “clk50MHz”;
OFFSET = IN 5 ns VALID 10 ns BEFORE clk TIMEGRP ClkIn_Rising;
OFFSET = IN -5 ns VALID 10 ns BEFORE clk TIMEGRP ClkIn_Falling;
为了进一步明确OFFSET语法中前后两个TIMEGRP用意的不同,下面给出如果要对一个两位宽的dIn输入端口添加DDR约束的例子:
NET “dIn<0>” TNM = dInG;
NET “dIn<1>” TNM = dInG;
TIMEGRP “ClkIn_Rising” = RISING “clk50MHz”;
TIMEGRP “ClkIn_Falling” = FALLING “clk50MHz”;
TIMEGRP “dInG” OFFSET = IN 5 ns VALID 10 ns BEFORE clk TIMEGRP ClkIn_Rising;
TIMEGRP “dInG” OFFSET = IN -5 ns VALID 10 ns BEFORE clk TIMEGRP ClkIn_Falling;

MDR输入约束

MDR的概念请回顾【程序设计篇->编程思路->关于外接接口的编程思路->按时钟特性分类->同步接口->MDR】小节。
类似的,既然是同步接口,那么我们必须首先为同步时钟定义一个周期约束,例如:
NET “clk” TNM_NET = clk50MHz;
TIMESPEC TS_clk = PERIOD “clk50MHz” 20 ns HIGH 50%;
由于MDR在实际接收时,往往还是通过SDR或者DDR的模式去进行数据接收,因此,如果实际采用的是SDR模式,则我们只需要采样对一个数据即可连续采集对所有的数据;而如果实际采用的是DDR模式,则我们只需要采样对连续两个数据即可连续采集对所有的数据。
那么,接下来以时钟数据比为1:4,数据变化沿对齐时钟变化沿的MDR为例,看看该如何应对其输入约束的描述:
首先,来看看SDR模式实现MDR采样。如果内部使用DCM(或者PLL),生成一个4倍频、同相的时钟信号,网络名为clk4x,则我们应该首先添加关于该生成时钟的周期约束如下:
NET “clk4x” TNM_NET = DCM4xOut;
TIMESPEC TS_ DCM4xOut = PERIOD “DCM4xOut” TS_clk / 4 HIGH 50%;
那么,由于clk4x与clk是相关时钟,所以时序分析工具会自动分析其跨时钟域的问题,故只需要基于clk给出一个数据采样的输入约束如下即可:
OFFSET = IN 5 ns VALID 5 ns BEFORE clk;
事实上,由于UCF文件是在布局布线前添加给ISE的,因此ISE会在编译的时候自动为DCM或PLL的输出生成关联周期约束,所以关于clk4x的周期约束可省略。

接下来,再看看DDR模式实现MDR采样。此时,由于具体完成采样的时钟并不是clk,所以不能采用【DDR输入约束】小节中的方法一。但若要采用方法二,必须建立关于具体采样时钟的两个边沿分组。因此,先为DCM的输出pin脚添加关联时钟约束如下:
PIN “instance_name/DCM_ADV_INST.CLK2X” TNM_NET = clk100MHz;
TIMESPEC TS_clk100MHz = PERIOD “clk100MHz” TS_clk / 2 HIGH 50%;
然后才能定义DDR采样时钟的两个分组如下:
TIMEGRP “Clk2x_Rising” = RISING “clk100MHz”;
TIMEGRP “Clk2x_Falling” = FALLING “clk100MHz”;
最后,基于clk信号描述连续的两个采样并关联到上述两个分组中即可:
OFFSET = IN 5 ns VALID 5 ns BEFORE clk TIMEGRP Clk2x_Rising;
OFFSET = IN -5 ns VALID 5 ns BEFORE clk TIMEGRP Clk2x_Falling;
事实上,由于UCF文件是在布局布线前添加给ISE的,因此ISE会在编译的时候自动为DCM或PLL的输出生成关联周期约束,所以下面这句话可省略:
TIMESPEC TS_clk100MHz = PERIOD “clk100MHz” TS_clk / 2 HIGH 50%;

差分输入约束

如果接口的输入数据是差分形式的,那么你需要在创建输入分组的时候把它们都加进去,然后一起添加输入约束即可。

组间约束

组间约束通过使用“FROM……TO”关键字,来对两时序分组之间的延迟给出限制描述。其基本语法定义如下:
TIMESPEC “TS_name”=FROM “group1” TO “group2” [DATAPATHONLY];
其中,
TIMESPEC "TS_name"为该路径约束定义了一个标示符,可供其他地方调用。
group1为路径起始端组。
group2 为路径目的端组。
指明组间延迟的最大允许范围。你无须指明最小允许范围,因为时序分析工具会自动为你报出起始端组和目的端组之间的最大、最小时间差。
[DATAPATHONLY]是可选参数,给出则表示当前组间约束将不考虑时钟skew、相位差等影响,而只考虑组间的数据路径延迟。

焊盘到焊盘路径约束

当FPGA设计中有不可拆解的纯组合逻辑接口时,就存在从芯片焊盘到焊盘的时序路径,此时,焊盘到焊盘的路径约束就会生效。可以直接使用预定义组PADS来对所有焊盘到焊盘的路径进行时序约束,描述如下:
TIMESPEC “TS_P2P” = FROM “PADS” TO “PADS” 20 ns;
此时,DATAPATHONLY关键字有没有都无所谓,因为焊盘到焊盘本身就是纯数据路径延迟。如果要对不同的焊盘之间添加不同的焊盘到焊盘的路径约束,则需要先创建自定义的起始焊盘组和目的焊盘组,然后再添加约束,例如:
TIMEGRP “dInG” = PADS(“a” “b”);
TIMEGRP “dOutG” = PADS(“c”);
TIMESPEC “TS_AB2C” = FROM “dInG” TO “dOutG” 20 ns;

多周期路径约束

在周期性约束的作用下,时序分析工具会认为该时钟域内寄存器的输出在每个时钟事件的到来都会发生变化,因此,理想情况下每个寄存器的保持时间均为一个时钟周期。可有时候,FPGA设计的功能特征决定前级寄存器需要经历很多个时钟周期后才会发生一次变化,这样一来,如果仅仅对该时钟域添加周期约束,显然对这部分电路是过约束了。如果这部分电路的逻辑比较简单,过约束并不会带来什么大问题;但如果这部分电路的逻辑比较复杂,过约束很可能会导致时序分析的时候不通过。因此,为了能够正确的对这部分逻辑添加时序约束,需要要使用多周期路径约束,例如如下描述:
NET “clk” TNM_NET = clk50MHz;
TIMESPEC TS_clk50MHz = PERIOD “clk50MHz” 20 ns HIGH 50%;

INST "b1" TNM = gb1;
INST "b2" TNM = gb2;
TIMESPEC TS_MultiPath = FROM gb1 TO gb2 TS_clk50MHz * 2;
在时序约束里,通常更为具体的约束比更为广泛的约束优先级要高,因此,虽然上例在最开始已经给所有clk50MHz分组添加了周期约束,但后续的多周期路径约束将b1、b2之间的周期约束改为2倍的多周期路径约束。

跨时钟域路径约束

如果两个时钟之间并不相关,默认情况下,时序分析工具是不会对这种跨时钟域情况进行分析的。但当它们之间又确实有着信息传递,而你又关心其间的一些时间延迟时,可以使用跨时钟域路径约束。例如如下描述:
NET “clk1” TNM_NET = clkA1;
TIMESPEC TS_clkA1 = PERIOD “clkA1” 20 ns HIGH 50%;
NET “clk2” TNM_NET = clkA2;
TIMESPEC TS_clkA2 = PERIOD “clkA2” 15 ns HIGH 50%;

TIMESPEC TS_CCR = FROM clkA1 TO clkA2 10 ns;
上例中的两条周期约束描述可省略,写明只是为了说明这两个时钟确实是无关的。如果只关心两个时钟域之间的数据路径延迟的话,可以将上例中的跨时钟域路径约束改为:
TIMESPEC TS_CCR = FROM clkA1 TO clkA2 10 ns DATAPATHONLY;
这样时序分析工具在分析的时候就不会考虑时钟skew等因素了,即便clk1、clk2是相关时钟。

跨时钟域忽略约束

如果两个时钟之间确实是相关的,例如DCM或者PLL的多个输出和它们的输入、一个时钟信号的上升沿和下降沿等,但我们又不希望时序分析工具对它们之间进行跨时钟域分析,此时可以使用跨时钟域忽略约束。例如如下描述:
NET “clk1” TNM_NET = clkA1;
TIMESPEC TS_clkA1 = PERIOD “clkA1” 20 ns HIGH 50%;
NET “clk2” TNM_NET = clkA2;
TIMESPEC TS_clkA2 = PERIOD “clkA2” TS_clkA1/2 HIGH 50%;

TIMESPEC TS_FastPath = FROM clkA1 TO clkA2 TIG;
上例中,通过在组间约束中使用TIG关键字,可以让时序分析工具不去分析从clkA1到clkA2的组间延迟。如果希望也不要分析从clkA2到clkA1的组间延迟,则还需要再添加一句描述如下:
TIMESPEC TS_FastPath = FROM clkA2 TO clkA1 TIG;

如果只是希望对两个时钟域之间的某一部分信号传递进行忽略,则可以先定义分组,然后再使用跨时钟域忽略约束。承接上例,如果希望忽略clk1时钟域中的aLock到clk2时钟域中c之间的跨时钟域分析,可描述如下:
INST “aLock” TNM = ta;
INST “c” TNM = tc;

TIMESPEC TS_FastPath = FROM ta TO tc TIG;

路径中间点约束

有时候,你关心的可能不仅仅是两个时序分组之间的全部路径延迟中的最大、最小情况,而是关心通过某一个中继点或组的两个时序分组之间的路径延迟中的最大、最小情况。此时,可以使用THRU关键字指明该中继分组。例如如下描述:
NET “a_3_IBUF” TPTHRU = “ta”;
TIMESPEC “TS_P2P” = FROM “PADS” THRU “ta” TO “PADS” 20 ns;
上例只分析那些焊盘到焊盘之间经过ta分组的路径延迟情况。

输出约束

输出约束主要针对输出接口,通过使用“OFFSET = OUT”关键字,实现对输出接口的一些基本时序要求描述,它的基本语法定义如下:
[{TIMEGRP|NET} “iobgroup_or_padnet_name”] OFFSET = OUT [units] {BEFORE|AFTER} “clk_name” [TIMEGRP “group_name”] {HIGH|LOW};
其中,
[{TIMEGRP|NET} “iobgroup_or_padnet_name”]可以为该输出约束指明一个网络或者一个分组(注意,这里的网络必须是连接到pad的网络,分组也必须是IO block相关的分组),若省略不写,则该约束的作用范围是全局的(应用于所有被时钟"clk_name"相关的输出端口)。
"clk_name"指明了该输出约束是相对于哪一个时钟事件的初始边沿来说的,注意,"clk_name"是一个输入时钟的名称,而不是输出时钟的名称,更确切的说,它是该约束所针对输出端口在FPGA内部所连接寄存器的驱动时钟。
、{BEFORE|AFTER} 、[TIMEGRP “group_name”]、{HIGH|LOW}与输入约束解释相同。

可见,ISE的输出约束不太智能,通过使用“OFFSET = OUT”关键字,只能描述输出端口相对于其输出寄存器驱动时钟之间的时间延迟是否能够满足一些基本要求,因此对于同步输出接口,ISE自带的时序分析工具不能直接给出分析结果。下面就来介绍一下该如何利用时序分析工具间接得到同步输出端口的时序报告。

直接同步输出约束

直接同步输出对应于【本篇->时序分析的原理->其他常见逻辑情形的应对方法->纯输出接口->纯同步输出接口】小节中描述的情况。可见,对于此类接口,ISE只能采用该小节中介绍的第三点方法来进行应对。即首先通过功能仿真获得clk与D信号在理想情况下的关系,然后再分别获取clk、D信号实际输出时的最大、最小延迟,然后人工计算得出针对该同步输出接口的时序分析结果。
如果内部时钟的周期约束如下:
NET “innerClk” TNM_NET = innerClk;
TIMESPEC TS_innerClk = PERIOD “innerClk” 20 ns HIGH 50%;
则,对于该同步输出接口,我们需要先定义针对数据D的输出约束,类似如下:
NET “D<0>” TNM = gDout;
NET “D<1>” TNM = gDout;
NET “D<2>” TNM = gDout;
NET “D<3>” TNM = gDout;
NET “D<4>” TNM = gDout;
NET “D<5>” TNM = gDout;
NET “D<6>” TNM = gDout;
NET “D<7>” TNM = gDout;
TIMEGRP “gDout” OFFSET = OUT 20 ns AFTER “innerClk”;
然后,再参考【组间约束中->焊盘到焊盘路径约束】小节中的方法,对innerClk与clk之间进行约束,类似如下:
TIMEGRP “gClkIn” = PADS(“innerClk”);
TIMEGRP “gClkOut” = PADS(“clk”);
TIMESPEC “TS_C2C” = FROM “gClkIn” TO “gClkOut” 20 ns;
这样,时序分析工具会报出D、clk相对于0时刻innerClk边沿的最大、最小延迟,最后结合功能仿真的情况即可人工得出该直接同步输出接口的时序分析报告。

间接同步输出约束

间接同步输出对应于【本篇->时序分析的原理->其他常见逻辑情形的应对方法->纯输出接口->异步生成同步输出】小节中描述的情况。
间接同步输出与直接同步输出的应对方法类似,唯一的不同就在于输出时钟clk相对于innerClk来说也是一个数据。因此,只需要将【直接同步输出约束】小节中,关于innerClk与clk之间的组间约束改为输出约束即可。类似如下:
NET “clk” TNM = gCout;
TIMEGRP “gCout” OFFSET = OUT 20 ns AFTER “innerClk”;
这样,时序分析工具会报出D、clk相对于0时刻innerClk边沿的最大、最小延迟,最后结合功能仿真的情况即可人工得出该间接同步输出接口的时序分析报告。

差分输出约束

如果接口的输出数据是差分形式的,那么你需要在创建输出分组的时候把它们都加进去,然后一起添加输出约束即可。

你可能感兴趣的:(#,FPGA之道精选)