组合逻辑生成时钟的典型特征是在网表中我们能够看到LUT(查找表)的输出直接连接或通过BUFG连接到时序逻辑单元比如触发器的时钟端口。最直接的危害是组合逻辑可能会产生毛刺(Glitch),从而导致电路功能错误。看个案例,如下图所示。由于毛刺的存在,计数器多计数了一次,导致错误。
从时序角度而言,组合逻辑生成的时钟会增加时钟线上的延迟,从而导致过大的Clock Skew,最终造成建立时间和保持时间违例。此外,如果有毛刺,毛刺通常很窄,很可能无法满足触发器的Pulse Width要求。还有的工程中尽管没有直接把LUT的输出当作时钟,而是将其通过一个触发器之后再用作时钟,这可以过滤掉毛刺,但同样会增加时钟线上的延迟,导致Clock Skew过大。因此,在FPGA设计中,要避免此类时钟。
拿到一个网表,如何判定设计中是否包含此类时钟呢?从上面的描述可以看到,这类时钟要么是LUT输出,要么是触发器输出,这是第一个特征。第二个特殊,既然是时钟,时钟网线的类型就是LOCAL_CLOCK,根据这两点就能找到时钟管脚,相应的Tcl脚本如下图所示。
代码第2行是找到所有的时钟网线,第3行对该时钟网线进行过滤筛选,凡是与网线相连的pin是输出端口且其REF_PIN_NAME是O(对应LUT输出)或Q(对应触发器输出)的,即为目标时钟端口。代码第4行则是将找到的对象以图形界面方式显示出来。
找到了这类时钟,如何优化呢?如果这类时钟是在MMCM或PLL可生成频率范围内,那么建议用MMCM或PLL生成,尤其是该时钟扇出比较大的时候。如果MMCM或PLL无法生成,且时钟频率很低,例如低于5MHz,而设计已经到了后期,不太可能大范围修改,那么尝试是否可能将该时钟驱动的逻辑都放在一个时钟区域内,同时保证时钟源也在该时钟区域内,这可通过手工布局的方式(画Pblock)实现。这样做对于降低Clock Skew会有些帮助。