FPGA时钟约束

铁佛  金牌会员 | 2025-3-21 17:56:27 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 983|帖子 983|积分 2949

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
  
   目录
  
  前言
  一、Create_clock
  
前言

时钟周期约束,就是对时钟举行约束。

一、Create_clock

create_clock -name <name> -period <period> -waveform {<rise_time> <fall_time>} [get_ports <input_port>]
<name>是时钟名字
<period>是时钟周期,单位ns
<rise_time>上升沿时刻
<fall_time>下降沿时刻
这里的时钟必须是主时钟,有两种环境:由外部时钟源提供,另一种是高速收发器的时钟,RXOUTCLK或TXOUTCLK。对于7系列FPGA,需要对GT的这两个时钟手工约束:对于UltraScale FPGA,只需对GT的输入时钟约束即可,Vivado会自动对这两个时钟约束。
端口(port)的管脚(pin)的区别。
端口是FPGA的IO端口,对应的XDC下令,get_ports。
管脚是FPGA内部的子模块的Pin,对应的是get_pins。
除了上面的时钟外,另有其他的办法确定时钟是不是主时钟,用Tcl脚本。
在Open Synthesized Design或者Open Implementation Design,并通过以下两种方式检察主时钟。
方式一:
运行tcl指令report_clock_networks -name mainclock
方式二:
运行tcl指令check_timing -override_defaults no_clock
对于高速收发器的时钟,我们也以Vivado中的CPU example工程为例,看下Xilinx官方是怎么约束的。
  1. # Define the clocks for the GTX blocks
  2. create_clock -name gt0_txusrclk_i -period 12.8 [get_pins mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt0_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK]
  3. create_clock -name gt2_txusrclk_i -period 12.8 [get_pins mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt2_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK]
  4. create_clock -name gt4_txusrclk_i -period 12.8 [get_pins mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt4_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK]
  5. 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参数。如果有两个主时钟,如下图所示。

对应的时钟约束为:
  1. create_clock -name clk0 -period 10.0 -waveform {0 5} [get_ports clk0]
  2. create_clock -name clk1 -period 8.0 -waveform {2 8} [get_ports clk1]
复制代码
这里应该是指高电平的一连时间,周期是10,0到5ns是高电平。
周期是8ns,高电平常间是2到8ns。
约束中的数字的单位默认是ns,若不写wavefrom参数,则默认是占空比为50%且第一个上升沿出现在0时刻。利用report_clocks指令可以检察约束是否生效。还是上面的CPU的例子,把约束都还原到最初的状态。执行report_clocks后,如下所示,我们只列出其中几项内容。
  1. Clock Report
  2. Clock           Period(ns)  Waveform(ns)    Attributes  Sources
  3. sysClk          10.000      {0.000 5.000}   P           {sysClk}
  4. gt0_txusrclk_i  12.800      {0.000 6.400}   P           {mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt0_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK}
  5. ...
  6. ====================================================
  7. Generated Clocks
  8. ====================================================
  9. Generated Clock   : clkfbout
  10. Master Source     : clkgen/mmcm_adv_inst/CLKIN1
  11. Master Clock      : sysClk
  12. Multiply By       : 1
  13. Generated Sources : {clkgen/mmcm_adv_inst/CLKFBOUT}
  14. Generated Clock   : cpuClk_4
  15. Master Source     : clkgen/mmcm_adv_inst/CLKIN1
  16. Master Clock      : sysClk
  17. Edges             : {1 2 3}
  18. Edge Shifts(ns)   : {0.000 5.000 10.000}
  19. Generated Sources : {clkgen/mmcm_adv_inst/CLKOUT0}
复制代码
一般来讲,我们的输入时钟都是差分的,此时我们只对P端举行约束即可。如果同时约束了P端和N端,通过report_clock_interaction下令可以看到提示unsafe。这样既会增长内存开销,也会延伸编译时间。
二、create_generated_clock

  1. create_generated_clock -name <generated_clock_name> \
  2.                        -source <master_clock_source_pin_or_port> \
  3.                        -multiply_by <mult_factor> \
  4.                        -divide_by <div_factor> \
  5.                        -master_clock <master_clk> \
  6.                        <pin_or_port>
复制代码
-name 时钟的名字
-source产生该时钟的源时钟
-multiply_by源时钟的多少倍频
-divide_by源时钟的多少分频
这个是约束FPGA内部的衍生时钟,所以有个-source,这个时钟叫做Master clokc,指的是上级时钟,为生成时钟提供时钟的时钟,和primary clock是不同的。这个master clock可以是主时钟也可以是其他的衍生时钟,没有主时钟那么多限制。
这个下令不是设定周期或波形,而是形貌电路如何对上级时钟举行转换。
这种转换可以是:


  • 简朴的频率分频
  • 简朴的频率倍频
  • 频率倍频与分频的组合,得到一个非整数的比例,通常由MMCM或PLL完成
  • 相移或波形反相
  • 占空比改变
  • 上述全部关系的组合
衍生时钟有两种环境。vivado自动推导的衍生时钟,用户自定义的衍生时钟,自定义的就是上面的。
首先来看第一种,如果利用PLL或者MMCM,则Vivado会自动推导出一个约束。大家可以打开Vivado中有个叫wavegen的工程,在这个工程中,输入时钟经过PLL输出了2个时钟,如下图所示。

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

有三个约束是由于PLL会自动输出一个反馈时钟。
自动推导的好处在于当MMCM/PLL/BUFR的设置改变而影响到输出时钟的频率和相位时,用户无需改写约束,Vivado仍然可以自动推导出精确的频率/相位信息。劣势在于,用户并不清楚自动推导出的衍生钟的名字,当计划条理改变时,衍生钟的名字也有可能改变。但由于该衍生时钟的约束并非我们自定义的,因此可能会没有关注到它名字的改变,当我们利用这些衍生时钟举行别的约束时,就会出现错误。
就是名字要取好,不要重复了。
解决办法是用户本身手动写出自动推导的衍生时钟的名字,也仅仅写出名字即可,其余的不写。如下所示。
  1. create_generated_clock -name <generated_clock_name> \
  2.                        -source <master_clock_source_pin_or_port>
复制代码
这一步很容易会被提示critical warning,实在有个很简朴的方法,就是name和source都按照vivado中生成的来。
三、set_clock_groups

利用方法是:
  1. set_clock_groups -asynchronous -group <clock_name_1> -group <clock_name_2>
  2.  set_clock_groups -physically_exclusive  -group <clock_name_1> -group <clock_name_2>
复制代码
这个约束常用的方法有三种,第一种用法是当两个主时钟是异步关系时,利用asynchronous来指定。这个在我们平常用的还是比力多的,一般轻微大点的工程,都会出现至少两个主时钟,而且这两个时钟之间并没有任何的相位关系,这时就要指定:
  1. create_clock -period 10 -name clk1 [get_ports clk1]
  2. create_clock -period 8 -name clk2 [get_ports clk2]
  3. set_clock_groups -asynchronous -group clk1 -group clk2
复制代码
第二种用法是当我们需要验证同一个时钟端口在不同时钟频率下可否得到时序收敛时利用。好比有两个异步主时钟clk1和clk2,需要验证在clk2频率为100MHz,clk1频率分别为50MHz、100MHz和200MHz下的时序收敛环境,我们就可以这样写。
  1. create_clock -name clk1A -period 20.0 [get_ports clk1]
  2. create_clock -name clk1B -period 10.0 [get_ports clk1] -add
  3. create_clock -name clk1C -period 5.0  [get_ports clk1] -add 
  4. create_clock -name clk2 -period 10.0 [get_ports clk2]
  5. set_clock_groups -physically_exclusive -group clk1A -group clk1B -group clk1C
  6. set_clock_groups -asynchronous -group "clk1A clk1B clk1C" -group clk2
复制代码
第三种用法就是当我们利用BUFGMUX时,会有两个输入时钟,但只会有一个时钟被利用。好比MMCM输入100MHz时钟,两个输出分别为50MHz和200MHz,这两个时钟进入了BUFGMUX,如下图所示。

  1. set_clock_groups -logically_exclusive \
  2. -group [get_clocks -of [get_pins inst_mmcm/inst/mmcm_adv_inst/CLKOUT0]] \
  3. -group [get_clocks -of [get_pins inst_mmcm/inst/mmcm_adv_inst/CLKOUT1]]
复制代码
四、创建假造时钟

假造时钟用于设定输入和输出的延迟约束。
这个约束实在是属于IO约束中的延迟约束。
假造时钟,就是没有与之绑定的物理管脚。
假造时钟主要用于以下三个场景:


  • 外部IO的参考时钟并不是计划中的时钟
  • FPGA I/O路径参考时钟来源于内部衍生时钟,但与主时钟的频率关系并不是整数倍
  • 针对I/O指定不同的jitter和latency
如下图所示,在FPGA的A和B端口分别有两个输入,其中捕捉A端口的时钟是主时钟,而捕捉B端口的时钟是MMCM输出的衍生时钟,而且该衍生时钟与主时钟的频率不是整数倍关系。

  1. create_clock -name sysclk -period 10 [get_ports clkin]
  2. create_clock -name virclk -period 6.4
  3. set_input_delay 2 -clock sysclk [get_ports A]
  4. 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延迟之前被定义。
五、最大最小延迟约束

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


  • 输入管脚的信号经过组合逻辑后直接输出到管脚
  • 异步电路之间的最大最小延迟

设置方式为:
  1. set_max_delay <delay> [-datapath_only] [-from <node_list>][-to <node_list>][-through <node_list>]
  2. set_min_delay <delay> [-from <node_list>] [-to <node_list>][-through <node_list>]
复制代码
-form有效的起始节点包含:时钟,input(input)端口,或时序单元(寄存器,RAM)的时钟引脚.
-to有效的停止节点包含:时钟,output(inout)端口或时序单元的数据端口.
-through有效的节点包含:引脚,端口,线网.
max/min delay的约束平常用的相对少一些,由于在跨异步时钟域时,我们每每会设置asynchronous或者false_path。对于异步时钟,我们一般都会通过计划来保证时序可以或许收敛,而不是通过时序约束来保证。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

铁佛

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表