[FPGA14]梳理时钟树_基本时钟_衍生时钟

梳理时钟树,基本时钟,衍生时钟

梳理时钟树

  • 在进行所有时序约束操作的开始之前,我们有必要对项目工程的时钟树进行梳理。

何为时钟树

所谓时钟树,就是工程中用到了哪些时钟,各个时钟之间的关系又是什么样的。如果自己都没有把时钟关系理清楚,就难以去进行对应的时钟约束。

工程举例

  • 以Vivado自带的wave_gen工程为例,该工程的各个模块功能较为明确,如下图所示。为了引入异步时钟域,我们在此程序上由增加了另一个时钟clkin2,该时钟产生脉冲信号pulse,samp_gen中在pulse为高时才产生信号。
  • 在这个工程中,有两个主时钟,四个衍生时钟,如下图所示。
  • 确定了主时钟和衍生时钟后,再看各个时钟是否有交互,即clka产生的数据是否在clkb的时钟域中被使用。这个工程比较简单,只有两组时钟之间有交互,即:
  1. clk_rx与clk_tx
  2. clk_samp与clk2
  • 其中,clk_rx和clk_tx都是从同一个MMCM输出的,两个频率虽然不同,但他们却是同步的时钟,因此他们都是从同一个时钟分频得到(可以在Clock Wizard的Port Renaming中看到VCO Freq的大小),因此它们之间需要用set_false_path来约束;而clk_samp和clk2是两个异步时钟,需要用asynchronous来约束。具体的约束方法会在后续章节讲到。
  • 完成以上两步,就可以进行具体的时钟约束操作了。

基本时钟(create_clock)

XDC约束代码

  • 在Vivado中使用create_clock来创建时钟周期约束。使用方法为:
#-----使用< >标识的内容为填入值-----#
create_clock  -name <name>  -period <period>  \
    -waveform {<rise_time> <fall_time>}  \
    [get_ports <input_port>]
参数 含义
-name 时钟名称
-period 时钟周期(ns)
-waveform 波形参数,上升/下降沿时刻(ns)
-add 在同一时刻源上定义多个时钟使用
  • 需要注意,这里的时钟必须为主时钟(primary clock),主时钟通常有两种情形,一种是时钟由外部时钟源提供,通过时钟引脚进入FPGA,该时钟引脚绑定的时钟为主时钟;另一种是通过高速收发器(GT)的时钟RXOUTCLK或者TXOUTCLK。对于7系列FPGA,需要对GT的这两个时钟手工约束:对于UltraScale FPGA,只需对GT的输入时钟约束即可,Vivado会自动约束通过时钟引脚输入的时钟。

使用Tcl脚本主时钟

  • 如何确定哪些时钟为系统主时钟,就成了时钟周期约束的关键,除了可以通过主时钟的两种情形进行人为判断之外,还可以使用Tcl脚本进行自动判断。
  1. 在“Tcl console”窗口中,输入指令report_clock_networks -name mainclock,会自动弹出“Clock Networks”窗口,在窗口中可以看到主时钟信息以及他们驱动的模块数量。
  2. 在“Tcl console”窗口中,输入指令check_timing -override_defaults no_clock,在当前窗口中,会显示该工程还未约束的主时钟名称。

多个主时钟约束举例

  • 当系统中有多个主时钟,且这几个主时钟之间存在确定的相位关系时,需要用到-waveform参数。约束中的数字的单位默认是ns,若不写wavefrom参数,则默认是占空比为50%且第一个上升沿出现在0时刻。如果有如图所示的两个主时钟。
  • 则始终约束如下所示。
create_clock -name clk0 -period 10.0 -waveform {0 5} [get_ports clk0]
create_clock -name clk1 -period 8.0 -waveform {2 8} [get_ports clk1]

检查时钟约束的指令

  • 在完成约束后,可使用report_clocks指令查看时钟约束是否生效。
  • 对于输入的差分时钟,我们只对P端进行约束即可。如果同时约束了P端和N端,通过report_clock_interaction命令可以看到提示unsafe。这样既会增加内存开销,也会延长编译时间。

衍生时钟(create_group_clock)

XDC约束代码

#-----使用< >标识的内容为填入值-----#
create_generated_clock -name <generated_clock_name> \
    -source [<master_clock_source_pin_or_port>] \
    -multiply_by <mult_factor> \
    -divide_by <div_factor> \
    [<pin_or_port>]
#--- [<master_clock_source_pin_or_port>][<pin_or_port>]分别有以下两种写法 ---#
#--- [get_pins <module_name>/<pin_name>] ---#
#--- [get_ports <output_port>] ---#
参数 含义
-name 时钟名称
-source 产生该时钟的源时钟
-multiply_by 源时钟的倍频数
-divide_by 源时钟的分频数
  • 该指令用于约束我们在FPGA内部产生的衍生时钟,-source参数用于指定这个时钟是由哪里来的,,这个时钟叫做master clock,即指上级时钟。该时钟不同于上文说到的primary clock,它可以是源时钟primary clock,也可以是其他的衍生时钟。该约束指令用于描述时钟电路如何对于上级时钟进行分频、倍频的转换。
#-----使用< >标识的内容为填入值-----#
create_generated_clock -name <generated_clock_name> \
    -source [<master_clock_source_pin_or_port>] \
    -edge {<1 2 3 >} \
    -edge_shift {<2.5 0 2.5>} \
    [<pin_or_port>]
#--- [<master_clock_source_pin_or_port>][<pin_or_port>]分别有以下两种写法 ---#
#--- [get_pins <module_name>/<pin_name>] ---#
#--- [get_ports <output_port>] ---#
参数 含义
-name 时钟名称
-source 产生该时钟的源时钟
-edge 定义衍生时钟的3个边沿分别参照主时钟的第几个边沿
-edge_shift 生成衍生边沿相较参考边沿的偏移时间(ns)

备注:
1."-edge_shift"的值可以为正值,也可以是负值。
2. "-edge"参数中,主时钟的第几个边沿在计数时,既包括上升沿也包括下降沿。如第2个边沿,指的是主时钟第1个周期的下降沿;第5个边沿,指的是主时钟第3个周期的上升沿。
3. "-edge","-edge_shift"参数中,3个边沿分别为,第1个周期上升沿,第1个周期下降沿,第2个周期上升沿。

  • 其实不难看出,使用边沿"-edge"参数描述衍生时钟的上升沿和下降沿的描述方式,可以替代通过分频数"-divide_by"与倍频数"-multiply_by"参数描述方式。需要注意的是,当有"-divide_by"或"-multiply_by"选项时,不能使用"-edge_shift"选项。

衍生时钟约束举例

  • 在第一个时钟约束中,主时钟源为基本时钟源点的输入端口(port)"clkin",对其进行2倍倍频和3倍分频后,从REGA模块的Q引脚(pin)输出。具体XDC约束代码与时钟波形如下所示。
create_clock -name clkin -period 10 [get_ports clkin]
create_generated_clock -name clk_mul2_div3 -source [get_ports clkin] \
    -multiply_by 2  -divide_by 3 \
    [get_pins REGA/Q]
  • 在第二个时钟约束中,"clkin"为主时钟,其属性表示为周期为10ns,占空比为50%。该时钟通过连接mmcm模块,由该模块产生一个新的时钟,新时钟的属性表示为占空比为83.33%,即56\frac{5}{6},,周期为原时钟的1.5倍,初始相移为60°。这个衍生时钟参照主时钟的第1,2,4个边沿进行定义,分别在主时钟源边沿的2.5ns,0ns,2.5ns后发生。具体XDC约束代码与时钟波形如下所示。
create_clock -name clkin -period 10 [get_ports clkin]
create_generated_clock -name clkshift -source [get_pins mmcm/CLKIN] \
    -edges{1 2 4} -edge_shift{2.5 0 2.5} \
    [get_pins mmcm0/CLKOUT]

自动推导的衍生时钟

  • 衍生时钟除了通过自定义的方式生成外,还可通过Vivado自动推导的方式生成。如果在工程中使用了PLL或者MCMM模块,则Vivado会自动推导出一个约束。使用report_clocks指令,则可以看到自动生成的衍生时钟约束。
  • 自动推导的好处在于当MMCM/PLL/BUFR的配置改变而影响到输出时钟的频率和相位时,用户无需改写约束,Vivado仍然可以自动推导出正确的频率/相位信息。劣势在于,用户并不清楚自动推导出的衍生钟的名字,当设计层次改变时,衍生钟的名字也有可能改变。但由于该衍生时钟的约束并非我们自定义的,因此可能会没有关注到它名字的改变,当我们使用者这些衍生时钟进行别的约束时,就会出现错误。
  • 所以我们可以自己手动写出自动推导的衍生时钟的名字,也仅仅写出名字即可,其余的不写。还需注意的是,name和source推荐都按照vivado中生成的来,否则可能会被提示"critical warning"。具体书写如下所示。
create_generated_clock -name <generated_clock_name> \
    -source <master_clock_source_pin_or_port>

参考:

  1. FPGA时序约束理论篇之时钟周期约束-Author:猫叔
  2. 《Xilinx FPGA权威设计指南--基于Vivado2018集成开发环境》,何宾,电子工业出版社