IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 数字IC&FPGA设计之时序约束(Part1) -> 正文阅读

[嵌入式]数字IC&FPGA设计之时序约束(Part1)

周期约束理论

时序约束:

????????目的是告诉软件(Vivado、ISE等)从哪个pin输入信号,输入信号要延迟多长时间,时钟周期是多少,让软件PAR(Place and ?Route)后的电路能够满足我们的要求。因此如果我们不加时序约束,软件是无法得知我们的时钟周期是多少,PAR后的结果是不会提示时序警告的。

??周期约束就是告诉软件我们的时钟周期是多少,让它PAR后要保证在这样的时钟周期内时序不违规。大多数的约束都是周期约束,因为时序约束约的最多是时钟。

建立和保持时间由器件决定,Xilinx FPGA的setup time基本都在0.04ns的量级,hold time基本在0.2ns的量级,不同器件会有所差异,具体可以查对应器件的DC and AC Switching Characteristics

时序路径

????????典型的时序路径有4类,如下图所示,这4类路径可分为片间路径(标记①和标记③)和片内路径(标记②和标记④)。

图片

????????对于所有的时序路径,我们都要明确其起点和终点,这4类时序路径的起点和终点分别如下表。

时序路径起点终点应用约束
①输入端口到FPGA内部第一级触发器的路径ChipA/clkrega/Dset_input_delay
②FPGA内部触发器之间的路径rega/clkregb/Dcreate_clock
③FPGA内部末级触发器到输出端口的路径regb/clkChipB/Dset_output_delay
④FPGA输入端口到输出端口的路径输入端口输出端口set_max_delay

????????这4类路径中,我们最为关心是②的同步时序路径,也就是FPGA内部的时序逻辑。

时序模型

????????典型的时序模型如下图所示,一个完整的时序路径包括源时钟路径、数据路径和目的时钟路径,也可以表示为触发器+组合逻辑+触发器的模型。

图片

该时序模型的要求为(公式1)

Tclk ≥ Tco + Tlogic + Trouting + Tsetup - Tskew  

????????其中,Tco为发端寄存器时钟到输出时间;Tlogic为组合逻辑延迟;Trouting为两级寄存器之间的布线延迟;Tsetup为收端寄存器建立时间;Tskew为两级寄存器的时钟歪斜,其值等于时钟同边沿到达两个寄存器时钟端口的时间差;Tclk为系统所能达到的最小时钟周期。

????????这里我们多说一下这个Tskew,skew分为两种,positive skew和negative skew,其中positive skew见下图,这相当于增加了后一级寄存器的触发时间。

图片

但对于negative skew,则相当于减少了后一级寄存器的触发时间,如下图所示。

图片

当系统稳定后,都会是positive skew的状态,但即便是positive skew,综合工具在计算时序时,也不会把多出来的Tskew算进去。

??用下面这个图来表示时序关系就更加容易理解了。为什么要减去Tskew,下面这个图也更加直观。

图片

????????发送端寄存器产生的数据,数据经过Tco、Tlogic、Trouting后到达接收端,同时还要给接收端留出Tsetup的时间。而时钟延迟了Tskew的时间,因此有:
(公式2)

Tdata_path + Tsetup <= Tskew + Tclk

????????对于同步设计Tskew可忽略(认为其值为0),因为FPGA中的时钟树会尽量保证到每个寄存器的延迟相同。

公式中提到了建立时间,那保持时间在什么地方体现呢?

??保持时间比较难理解,它的意思是reg1的输出不能太快到达reg2,这是为了防止采到的新数据太快而冲掉了原来的数据。保持时间约束的是同一个时钟边沿,而不是对下一个时钟边沿的约束。

图片

reg2在边沿2时刻刚刚捕获reg1在边沿1时刻发出的数据,若reg1在边沿2时刻发出的数据过快到达reg2,则会冲掉前面的数据。因此保持时间约束的是同一个边沿。

图片

在时钟沿到达之后,数据要保持Thold的时间,因此,要满足:(公式3)

Tdata_path =  Tco + Tlogic + Trouting ≥ Tskew + Thold

? ? ? ?这两个公式是FPGA的面试和笔试中经常问到的问题,因为这种问题能反映出应聘者对时序的理解。

??在公式1中,Tco跟Tsu一样,也取决于芯片工艺,因此,一旦芯片型号选定就只能通过Tlogic和Trouting来改善Tclk。其中,Tlogic和代码风格有很大关系,Trouting和布局布线的策略有很大关系。

??关于时序约束的基本理论就讲这么多,下面讲具体的约束。

I/O约束

I/O约束是必须要用的约束,又包括管脚约束和延迟约束。

管脚约束

????????管脚约束就是指管脚分配,我们要指定管脚的PACKAGE_PIN和IOSTANDARD两个属性的值,前者指定了管脚的位置,后者指定了管脚对应的电平标准。

??在vivado中,使用如下方式在xdc中对管脚进行约束。

set_property -dict {PACKAGE_PIN AJ16  IOSTANDARD  LVCMOS18} [get_ports "led[0]"]

??? ? ?在Vivado规定,必须要指定管脚电平,不然在最后一步生成比特流时会出错。

??除了管脚位置和电平,还有一个大家容易忽略但很容易引起错误的就是端接,当我们使用差分电平时比如LVDS,在V6中我们使用IBUFDS来处理输入的差分信号时,可以指定端接为TRUE。

   IBUFDS #(
      .DIFF_TERM("TRUE"),       // Differential Termination
      .IOSTANDARD("DEFAULT")     // Specify the input I/O standard
   ) IBUFDS_inst (
      .O(O),  // Buffer output
      .I(I),  // Diff_p buffer input (connect directly to top-level port)
      .IB(IB) // Diff_n buffer input (connect directly to top-level port)
   );

? ? ? ?但在Ultrascale中的IBUFDS,却把端接这个选项去掉了

   IBUFDS #(
      .DQS_BIAS("FALSE")  // (FALSE, TRUE)
   )
   IBUFDS_inst (
      .O(O),   // 1-bit output: Buffer output
      .I(I),   // 1-bit input: Diff_p buffer input (connect directly to top-level port)
      .IB(IB)  // 1-bit input: Diff_n buffer input (connect directly to top-level port)
   );

????????我们必须要在xdc或I/O Ports界面中,手动指定,否则可能会出错。

图片

????????笔者(微信公众号:quant_times)之前就采过一个坑,差分端口输入,当连续输入的数据为11101111这种时,中间那个0拉不下来,还是1,同样也会发生在000010000,这样就导致数据传输错误,后来才发现是端接忘记加。因为端接会影响信号的实际电平,导致FPGA判断错误。

??当综合完成后,我们可以点击DRC,进行设计规则检查,这一步可以报出一些关键问题,比如时钟端口未分配在时钟引脚上等。

图片

?延迟约束

??应用于输入输出端口,延迟约束用的是set_input_delayset_output_delay,分别用于input端和output端,其时钟源可以是时钟输入管脚,也可以是虚拟时钟。但需要注意的是,这个两个约束并不是起延迟的作用,而只是周期约束,具体原因下面分析。

  • set_input_delay

??这个约束跟ISE中的OFFSET=IN功能相同,但设置方式不同。下图所示即为input delay的约束说明图。

图片

从图中很容易理解,

T_inputdelay = Tco + TD

当满足图中的时序时,最大延迟为2ns,最小延迟为1ns。

因此,需要加的时序约束为

create_clock -name sysclk -period 10 [get_ports clkin]//先创建时钟,周期为10ns
set_input_delay 2 -max -clock sysclk [get_ports Datain]//数据沿比时钟沿延时最大2ns
set_input_delay 1 -min -clock sysclk [get_ports Datain]//数据沿比时钟沿延时最小1ns
  • set_output_delay

??set_output_delay的用法跟set_input_delay十分相似,这里就不再展开讲了。我们上面讲set_input_delay的描述中,大家可以看到,这个约束是告诉vivado我们的输入信号(数据)和输入时钟之间的延迟关系,跟下面要讲的时钟周期约束是一个原理,让vivado在这个前提下去Place and Route。并不是调节输入信号的延迟,因为身边有不少的FPGA工程师在没用过这个约束指令之前,都以为这是调节延迟的约束。

??如果要调整输入信号的延迟,只能使用IDELAY,在V6中,IDELAY模块有32个tap值,每个tap可延迟78ps,这样总共差不多是2.5ns。

时钟周期约束

????????时钟周期约束,顾名思义,就是我们对时钟的周期进行约束,这个约束是我们用的最多的约束了,也是最重要的约束。

??下面我们讲一些Vivado中时钟约束指令。

1. Create_clock

????????在Vivado中使用create_clock来创建时钟周期约束。使用方法为:

create_clock -name <name> -period <period> -waveform {<rise_time> <fall_time>} [get_ports <input_port>]
//create_clock 创建时钟
参数含义
-name时钟名称
-period时钟周期,单位为ns
-waveform波形参数,第一个参数为时钟的第一个上升沿时刻,第二个参数为时钟的第一个下降沿时刻
-add在同一时刻源上定义多个时钟时使用

????????这里的时钟必须是主时钟primary clock主时钟通常有两种情形:一种是时钟由外部时钟源提供,通过时钟引脚进入FPGA,该时钟引脚绑定的时钟为主时钟:另一种是高速收发器(GT)的时钟RXOUTCLK或TXOUTCLK。对于7系列FPGA,需要对GT的这两个时钟手工约束:对于UltraScale FPGA,只需对GT的输入时钟约束即可,Vivado会自动对这两个时钟约束。

??如何确定主时钟是时钟周期约束的关键,除了根据主时钟的两种情形判断之外,还可以借助Tcl脚本判断。

??在vivado自带的example project里面,打开CPU(HDL)的工程,如下图所示。

图片

????????把工程的xdc文件中,create_clock的几项都注释掉。这里解释下端口(Port)和管脚(Pin)。get_ports获取的是FPGA的IO端口,get_pins获取的是FPGA内部子模块的Pin,具体的我们在第14讲的Tcl命令中会讲到。

图片

????????再Open Synthesized Design或者Open Implementation Design,并通过以下两种方式查看主时钟。

????????方式一

????????运行tcl指令report_clock_networks -name mainclock,显示结果如下:

图片

????????方式二
????????运行tcl指令check_timing -override_defaults no_clock,显示结果如下:

图片

Vivado中的tcl命令行相当好用,有很多的功能,大家可以开始习惯用起来了。

??对于高速收发器的时钟,我们也以Vivado中的CPU example工程为例,看下Xilinx官方是怎么约束的。

# Define the clocks for the GTX blocks
create_clock -name gt0_txusrclk_i -period 12.8 [get_pins mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt0_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK]
create_clock -name gt2_txusrclk_i -period 12.8 [get_pins mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt2_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK]
create_clock -name gt4_txusrclk_i -period 12.8 [get_pins mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt4_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK]
create_clock -name gt6_txusrclk_i -period 12.8 [get_pins mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt6_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK]

???当系统中有多个主时钟,且这几个主时钟之间存在确定的相位关系时,需要用到-waveform参数。如果有两个主时钟,如下图所示。

图片

?则时钟约束为:

create_clock -name clk0 -period 10.0 -waveform {0 5} [get_ports clk0]//周期为10ns,上升沿在0ns,下降沿在5ns,
create_clock -name clk1 -period 8.0 -waveform {2 8} [get_ports clk1]

约束中的数字的单位默认是ns,若不写wavefrom参数,则默认是占空比为50%且第一个上升沿出现在0时刻。使用report_clocks指令可以查看约束是否生效。还是上面的CPU的例子,把约束都还原到最初的状态。执行report_clocks后,如下所示,我们只列出其中几项内容。

Clock Report

Clock           Period(ns)  Waveform(ns)    Attributes  Sources
sysClk          10.000      {0.000 5.000}   P           {sysClk}
gt0_txusrclk_i  12.800      {0.000 6.400}   P           {mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt0_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK}
...


====================================================
Generated Clocks
====================================================

Generated Clock   : clkfbout
Master Source     : clkgen/mmcm_adv_inst/CLKIN1
Master Clock      : sysClk
Multiply By       : 1
Generated Sources : {clkgen/mmcm_adv_inst/CLKFBOUT}

Generated Clock   : cpuClk_4
Master Source     : clkgen/mmcm_adv_inst/CLKIN1
Master Clock      : sysClk
Edges             : {1 2 3}
Edge Shifts(ns)   : {0.000 5.000 10.000}
Generated Sources : {clkgen/mmcm_adv_inst/CLKOUT0}

????????一般来讲,我们的输入时钟都是差分的,此时我们只对P端进行约束即可。如果同时约束了P端和N端,通过report_clock_interaction命令可以看到提示unsafe。这样既会增加内存开销,也会延长编译时间。

2. create_generated_clock

????????其使用方法为:

create_generated_clock -name <generated_clock_name> \
                       -source <master_clock_source_pin_or_port> \
                       -multiply_by <mult_factor> \
                       -divide_by <div_factor> \
                       -master_clock <master_clk> \
                       <pin_or_port>
参数含义
-name时钟名称
-source产生该时钟的源时钟
-multiply_by源时钟的多少倍频
-divide_by源时钟的多少分频

????????从名字就能看出来,这个是约束我们在FPGA内部产生的衍生时钟, 所以参数在中有个-source,就是指定这个时钟是从哪里来的,这个时钟叫做master clock,是指上级时钟,区别于primary clock
????????它可以是我们上面讲的primary clock,也可以是其他的衍生时钟。该命令不是设定周期或波形,而是描述时钟电路如何对上级时钟进行转换。这种转换可以是下面的关系:

  • 简单的频率分频

  • 简单的频率倍频

  • 频率倍频与分频的组合,获得一个非整数的比例,通常由MMCM或PLL完成

  • 相移或波形反相

  • 占空比改变

  • 上述所有关系的组合

衍生时钟又分两种情况:

  1. Vivado自动推导的衍生时钟

  2. 用户自定义的衍生时钟

??首先来看第一种,如果使用PLL或者MMCM,则Vivado会自动推导出一个约束。大家可以打开Vivado中有个叫wavegen的工程,在这个工程中,输入时钟经过PLL输出了2个时钟,如下图所示。
(补充:关于DCM/DLL/PLL/MMCM的区别,可参考我写的另一篇文章DCM/DLL/PLL/MMCM区别

(在微信公证号Quant_Times中搜索就能看到)

图片

????????但在xdc文件中,并未对这2个输出时钟进行约束,只对输入的时钟进行了约束,若我们使用report_clocks指令,则会看到:

图片

注:有三个约束是因为PLL会自动输出一个反馈时钟

??自动推导的好处在于当MMCM/PLL/BUFR的配置改变而影响到输出时钟的频率和相位时,用户无需改写约束,Vivado仍然可以自动推导出正确的频率/相位信息。劣势在于,用户并不清楚自动推导出的衍生钟的名字,当设计层次改变时,衍生钟的名字也有可能改变。但由于该衍生时钟的约束并非我们自定义的,因此可能会没有关注到它名字的改变,当我们使用者这些衍生时钟进行别的约束时,就会出现错误。

??解决办法是用户自己手动写出自动推导的衍生时钟的名字,也仅仅写出名字即可,其余的不写。如下所示。

create_generated_clock -name <generated_clock_name> \
                       -source <master_clock_source_pin_or_port>

????????这一步很容易会被提示critical warning,其实有个很简单的方法,就是name和source都按照vivado中生成的来。具体我们到后面的例子中会讲到。

3. set_clock_groups

????????使用方法为:

set_clock_groups -asynchronous -group <clock_name_1> -group <clock_name_2>
set_clock_groups -physically_exclusive  -group <clock_name_1> -group <clock_name_2>

????????这个约束常用的方法有三种,第一种用法是当两个主时钟是异步关系时,使用asynchronous来指定。这个在我们平时用的还是比较多的,一般稍微大点的工程,都会出现至少两个主时钟,而且这两个时钟之间并没有任何的相位关系,这时就要指定:

create_clock -period 10 -name clk1 [get_ports clk1]
create_clock -period 8 -name clk2 [get_ports clk2]
set_clock_groups -asynchronous -group clk1 -group clk2//指定主时钟clk1和clk2异步

????????第二种用法是当我们需要验证同一个时钟端口在不同时钟频率下能否获得时序收敛时使用。比如有两个异步主时钟clk1和clk2,需要验证在clk2频率为100MHz,clk1频率分别为50MHz、100MHz和200MHz下的时序收敛情况,我们就可以这样写。

create_clock -name clk1A -period 20.0 [get_ports clk1]
create_clock -name clk1B -period 10.0 [get_ports clk1] -add
create_clock -name clk1C -period 5.0  [get_ports clk1] -add 
create_clock -name clk2 -period 10.0 [get_ports clk2]
set_clock_groups -physically_exclusive -group clk1A -group clk1B -group clk1C//physically_exclusive 指定时钟在物理上不会同时存在
set_clock_groups -asynchronous -group "clk1A clk1B clk1C" -group clk2

????????第三种用法就是当我们使用BUFGMUX时,会有两个输入时钟,但只会有一个时钟被使用。比如MMCM输入100MHz时钟,两个输出分别为50MHz和200MHz,这两个时钟进入了BUFGMUX,如下图所示。

图片

在这种情况下,我们需要设置的时序约束如下:

set_clock_groups -logically_exclusive \//在逻辑上只能有一个存在
-group [get_clocks -of [get_pins inst_mmcm/inst/mmcm_adv_inst/CLKOUT0]] \
-group [get_clocks -of [get_pins inst_mmcm/inst/mmcm_adv_inst/CLKOUT1]]

4. 创建虚拟时钟

??虚拟时钟通常用于设定对输入和输出的延迟约束,这个约束其实是属于IO约束中的延迟约束,之所以放到这里来讲,是因为虚拟时钟的创建,用到了本章节讲的一些理论。虚拟时钟和前面讲的延迟约束的使用场景不太相同。顾名思义,虚拟时钟,就是没有与之绑定的物理管脚。
虚拟时钟主要用于以下三个场景:

  • 外部IO的参考时钟并不是设计中的时钟

  • FPGA I/O路径参考时钟来源于内部衍生时钟,但与主时钟的频率关系并不是整数倍

  • 针对I/O指定不同的jitter和latency

??简而言之,之所以要创建虚拟时钟,对于输入来说,是因为输入到FPGA数据的捕获时钟是FPGA内部产生的,与主时钟频率不同;或者PCB上有Clock Buffer导致时钟延迟不同。对于输出来说,下游器件只接收到FPGA发送过去的数据,并没有随路时钟,用自己内部的时钟去捕获数据。

??如下图所示,在FPGA的A和B端口分别有两个输入,其中捕获A端口的时钟是主时钟,而捕获B端口的时钟是MMCM输出的衍生时钟,而且该衍生时钟与主时钟的频率不是整数倍关系。

图片

??这种情况下时序约束如下:

create_clock -name sysclk -period 10 [get_ports clkin]
create_clock -name virclk -period 6.4//没有对应的物理管脚,所以是虚拟时钟
set_input_delay 2 -clock sysclk [get_ports A]
set_input_delay 2 -clock virclk [get_ports B]

可以看到,创建虚拟时钟用的也是create_clock约束,但后面并没有加get_ports参数,因此被称为虚拟时钟。

??再举个输出的例子,我们常用的UART和SPI,当FPGA通过串口向下游器件发送数据时,仅仅发过去了uart_tx这个数据,下游器件通过自己内部的时钟去捕获uart_tx上的数据,这就需要通过虚拟时钟来约束;而当FPGA通过SPI向下游器件发送数据时,会发送sclk/sda/csn三个信号,其中sclk就是sda的随路时钟,下游器件通过sclk去捕获sda的数据,而不是用自己内部的时钟,这是就不需要虚拟时钟,直接使用set_output_delay即可。

注意,虚拟时钟必须在约束I/O延迟之前被定义。

5.最大最小延迟约束

??顾名思义,就是设置路径的max/min delay,主要应用场景有两个:

  • 输入管脚的信号经过组合逻辑后直接输出到管脚

  • 异步电路之间的最大最小延迟

    图片

    设置方式为:

    set_max_delay <delay> [-datapath_only] [-from <node_list>][-to <node_list>][-through <node_list>]
    set_min_delay <delay> [-from <node_list>] [-to <node_list>][-through <node_list>]
    参数含义
    -from有效的起始节点包含:时钟,input(input)端口,或时序单元(寄存器,RAM)的时钟引脚.
    -to有效的终止节点包含:时钟,output(inout)端口或时序单元的数据端口.
    -through有效的节点包含:引脚,端口,线网.

??max/min delay的约束平时用的相对少一些,因为在跨异步时钟域时,我们往往会设置asynchronous或者false_path。对于异步时钟,我们一般都会通过设计来保证时序能够收敛,而不是通过时序约束来保证。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-11-22 12:30:12  更:2021-11-22 12:32:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/8 4:37:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码