时序的零起点
用create_clock定义的主时钟的起点即时序的“零起点”,在这以前的上游路径都会被工具自动忽略。所以主时钟在哪个“点”很重要,以下图所示结构来举例,分别于FPGA输入端口和BUFG输出端口创建一个主时钟,在时序报告中体现出的路径延时完全不同,很明显sysclk_bad的报告中缺少了之前的一段的延时,时序报告不可信。
在同一个点上,由用户定义的时钟会覆盖工具自动推导的时钟,且后定义的时钟胡覆盖先定义的时钟。若要二者并存,必须使用-add选项。
Create_clock -name sysclk -period 10 [get_ports sys_clk]
Create_generated_clock -name clkbufg -source [get_ports sys_clk] -divide_by 1\
[get_pins clk_infra_i/clkfsm_buf/o]
Create_generated_clock -name clkbufr -source [get_ports sys_clk] -divide_by 1\
[get_pins clk_infra_i/clkfsm_buf/o] -add -master_clock sysclk
上述例子中的BUFG的输出端由用户自定义了一个衍生时钟clkbufg,这个衍生时钟会覆盖此处原有的sysclk。此外,图示BUFR工作在bypass模式,其输出不会自动创建衍生时钟,但在BUFR的输出端定义一个衍生时钟clkbufr,并使用-add和-master_clock选项后,这一点上会存在sysclk和clkbufg两个重叠的时钟。
不同于UCF约束,在XDC中,所有的时钟都会被缺省认为是相关的,也就是说,网表中所有存在的时序路径会被VIVADO分析。这也就意味着FPGA设人员必须通过约束告诉工具,哪些路径是无需分析的,哪些时钟域之间是异步的。
如上图所示,两个主时钟ssclkin和sysclk由不同的端口进入FPGA,在经过不同的时钟网络传递,要将它们设成异步时钟,可以使用下面的约束:
set_clock_groups -name sys_ss_async -asynchronous -group\
[get_clocks -include_generated_clocks sysclk] -group \
[get_clocks -include_generated_clocks ssclkin]
其中,-include_generated_clocks表示所有衍生时钟自动跟主时钟一组,从而与其他组的时钟时间为异步关系。不加这个选项则仅仅将时钟关系的约束应用在主时钟层面。
重置时钟是指多个时钟共享完全相同的时钟传输网络,例如两个时钟经过一个MUX选择后输出的时钟。
如下图所示,clk125个clk250是clkcore_buf的两个输入时钟,不约束时钟关系的情况下,VIVADO会对图示路径做跨时钟域分析。这样的时序报告即便没有违例,也是不可信的。因为clk125个clk250不可能同时驱动这条路径上的时序原件。这么做也会增加运行时间,并影响最终的实现结果。
如果clk125和clk250除了通过clkcore_buf后一模一样的删除外没有驱动其他时序元件,则只需要补齐时钟关系的约束。
set_clock_groups -physically_exclusive -group [get_clocks clk125]\
-group [get_clocks clk250]
在很多情况下,除了共同的扇出,其中一个时钟域或两个都还驱动其他的时序元件,此时建议的做法是在clkcore_clk的输出端建立两个重叠的衍生时钟,并将其时钟关系约束为-physically_exclusive表示不可能同时通过。这样做可以最大化约束覆盖率,也是ISE和UCF无法做到的。
create_generated_clock -name clk125_bufgctrl\
-divide_by 1 [get_pins bufgctrl_i/o]\
-source [get_ports bufgctrl_i/I0]
create_generated_clock -name clk250_bufgctrl
-divide_by 1 [get_pins bufgctrl_i/o]\
-source [get_ports bufgctrl_i/I1]\
-add -master_clock clk250
set_clock_groups -physically_exclusive \
-group clk125_bufgctrl\
-group clk250_bufgctrl