这次的SoC做了多时钟域处理,因此也比之前的约束起来会更复杂一些,把目前的一些小经验给总结一下。
首先描述一下这次的时钟域处理情况,对AXI总线上做了400MHz的时钟约束,AHB是二分频到200MHz,APB再二分频到100MHz,这是三路同步时钟,400MHz的时钟由PLL直接产生给到内部,200MHz和100MHz时钟是依次派生的时钟关系。此外还有一路单独的JTAG时钟,与上述时钟为异步关系。
因此这里涉及到的两个问题就是:1. 怎么约束派生时钟的关系,2. 怎么定义时钟间的异步关系。
先解决第一个问题,都知道派生时钟用create_generated_clock
命令去做,但这里的问题就是怎么和RTL代码结合起来,将时钟约束到哪个pin上。一个新手的常见误区是会去写一个计数器分频的模块,产生好分频后的时钟后,直接将时钟约束到模块的port上。我最早也是这么做的,然后就被后端怼了,这里的问题就是往往工具会在模块内部连接到port的路径上加buffer,因此内部产生的分频时钟传播到port上之后实际上就带有了buffer引入的延迟,导致产生相位差,破坏同步时钟的关系。合理的设置方法应该是在RTL中直接例化DFF,然后将产生的分频信号约束到DFF的Q端上,同理在FPGA上,如果不使用IP的话,那么就直接调用Vivado的DFF原语,然后进行约束。
第二个问题,异步关系怎么处理?这个情境下前三个时钟都是同步时钟,最后一个时钟和前三个时钟都是异步关系,如果只有两个异步时钟的话,相互设置set_flase_path
就完事了,但现在这样就比较麻烦,所以最好的办法是直接使用set_clock_groups -asynchronous
的方式来完成,简单明了。有个debug的小点是,为了便捷,这边用变量的方式声明的clock name,但是到命令里面去调用的时候发现类似于set_clock_groups -asynchronous -group [get_clocks {$clk1_name $clk2_name $clk3_name}] -group [get_clocks $clk4_name]
这种写法是不识别的,最后发现还是得老老实实声明一个list变量来处理。
最后直接放一下对应的RTL代码和sdc:
assign clk_400 = clk;
wire clk_200_inv;
wire clk_100_inv;
// clock divide register 0
assign clk_200_inv = ~clk_200;
DFCNQD0BWP7D5T20P96CPD u_div_reg0(.D(clk_200_inv), .CP(clk), .CDN(rst_n), .Q(clk_200));
// clock divide register 1
assign clk_100_inv = ~clk_100;
DFCNQD0BWP7D5T20P96CPD u_div_reg1(.D(clk_100_inv), .CP(clk_200), .CDN(rst_n), .Q(clk_100));
# Definition of Clock
set Tclk1 2.5 ; #400MHz
set Tclk2 5 ; #200MHz // generated clock
set Tclk3 10 ; #100MHz // generated clock
set Tclk4 1000 ; #1MHz
set clk1_name "clk_400"
set clk2_name "clk_200"
set clk3_name "clk_100"
set clk4_name "clk_jtag"
set unc_perc 0.05
create_clock -name $clk1_name -period $Tclk1 [get_ports clk]
set_clock_uncertainty -setup [expr $Tclk1 * $unc_perc] [get_clocks $clk1_name]
create_generated_clock -name $clk2_name -source [get_pins u_clk_rst_gen/u_div_reg0/CP] -divide_by 2 [get_pins u_clk_rst_gen/u_div_reg0/Q] -master_clock $clk1_name
create_generated_clock -name $clk3_name -source [get_pins u_clk_rst_gen/u_div_reg1/CP] -divide_by 2 [get_pins u_clk_rst_gen/u_div_reg1/Q] -master_clock $clk2_name
create_clock -name $clk4_name -period $Tclk4 [get_ports jtag_tck]
set_clock_uncertainty -setup [expr $Tclk4 * $unc_perc] [get_clocks $clk4_name]
set_clock_transition 0.4 [all_clocks]
set clk_list1 [list $clk1_name $clk2_name $clk3_name]
set clk_list2 [list $clk4_name]
set_clock_groups -asynchronous -group [get_clocks $clk_list1] -group [get_clocks $clk_list2]
标签:set,name,clock,clk,sdc,get,经验总结,时钟
From: https://www.cnblogs.com/sasasatori/p/18644635