在描述时序约束时,一个重要的原则是确保约束简洁高效。简洁高效意味着约束只针对指定的对象,即约束对应的对象的个数(通常这些对象由命令get_pins、get_cells、get_nets、get_ports或get_clocks获取)尽可能少,少的同时还要足够的精确,能够安全地覆盖到期望的时序路径。既不会出现遗漏某些对象也不会出现包含了不期望的对象,两者都会造成工具无法对相关路径按照指定要求进行时序分析,从而造成设计“伪收敛”。这通常会出现在使用-from、-to或-through等选项的约束中,例如:
set_clock_groups,set_false_path
set_max_delay,set_multicycle_path
等时序例外约束。
Vivado提供了一些方法用于分析时序例外约束的有效性,其中之一就是用命令report_exceptions生成时序例外报告。这里我们首先介绍一下这个命令的使用方法。
report_exceptions -scope_override
选项-scope_override可用于查看是否存在作用于某个子模块的约束(约束的作用域仅限于该子模块)被顶层约束部分或者全部覆盖。注意这里仅限于子模块约束与顶层模块约束之间的覆盖情况,而不会报告不同子模块之间的约束覆盖情况。借助此选项查看IP的约束是否被用户约束所覆盖将变得非常容易。如下图所示,我们可以在生成报告的Status列发现IP约束被用户约束覆盖。
report_exceptions -coverage
选项-coverage可查看约束的覆盖率,其描述形式是时序例外约束所施加的路径的起点或终点的pin个数与-from/-through/-to选项所获得的pin的个数的百分比。我们看一个例子,如下图所示报告。其中的红色方框可以看到这里使用的是set_max_delay,-from是通过get_cells获得的,因为只有1个cell且时序路径的起点是触发器的时钟端口,所以From的覆盖率就是100%(触发器只有1个时钟端口)。-to也是通过get_cells获取,获取到1个cell,这个cell也是触发器,其数据端口是该约束对应的时序路径的终点。但实际上,触发器除了数据端口之外,还有时钟使能端口/复位端口,所以To的覆盖率就是1/3也就是这里的33.33%。显然,覆盖率越高表明我们描述得越精确。
report_exceptions -ignored
选项-ignored可报告出设计中被完全覆盖的约束(Totally overridden),需要注意的是不会报告部分被覆盖的约束(Partially Overridden)。下图中可以看到set_multicycle_path被set_max_delay所覆盖。
report_exceptions -ignored_objects
选项-ignored_objects可报告出被忽略的起点或终点。之所以被忽略是因为这些路径不存在,例如下图中触发器的D端口恒接地,这样在使用set_false_path -to时,-to的值如果是通过get_pins获取到该触发器的D端口, 那么这条路径的终点就会被工具忽略,从而这条约束也就无效。
从编译时间的角度看,描述约束时越精确越好。一个事实是在网表中pin的个数通常是cell个数的几倍甚至几十倍,因此直接搜索pins会比较耗时,Xilinx推荐的方法是利用cell和pin的关系,先找到cell再找到对应的pin,例如:需要对下图所示的两个触发器对应的时序路径进行False Path约束,采用了三种方式。显然,方案1和方案2会覆盖到不期望的路径,方案3最为精确,耗时也较少。
尤其是当get_pins命令使用了通配符时,先get_cells再get_pins更为高效,如下图所示方式。
另外,在约束中避免使用all_registers,该命令会返回设计中的所有触发器。如果确需用all_registers,那么可通过选项-clock限定作用域,或者用get_clocks取代,如下图所示。
时序约束的描述顺序对编译时间也有很大影响。当时序约束被加载到内存时,时序引擎会对每条约束进行验证。对于可能存在问题的约束,时序引擎会打印出相关的信息。一些约束可能会导致部分时序数据库无效,还有一些约束可能需要更新时序数据库以便正常运行。例如,MMCM自动生成的时钟若频率或相位发生了改变,那么用到这个时钟的相关约束就需要更新。交织的时序约束以及影响到时序数据库的约束会对编译时间产生较大影响。如下表格显示了会对时序数据库产生影响的一些Tcl命令。
其中最为耗时的描述方式是同时使用了set_disable_timing和all_fanin或all_fanout,如下图所示。
根据上述表格,从编译时间的角度来看,最优的约束描述顺序是:
(2)影响时序数据库的约束如create_clock
我们看一个案例,如下图所示:代码第3至第10行为原始约束顺序,这里将set_disable_timing和set_case_analysis放在了create_clock之后。代码第14行至第20行为推荐的约束顺序,可以看到先描述set_disable_timing,之后是set_case_analysis,然后才是create_clock,同时将set_max_delay放在了最后。
没有回复内容