1. 时钟问题
在任何设计中,综合的最关键部分是时钟的描述,总是有关于布图前后定义的问题。
过去传统上在时钟源旁放置大的缓冲器以驱动整个时钟网络。在版图中使用粗时钟主干以获得时钟网络延时的均匀分布和最小化始终扭曲。但目前互联线RC延时为总延时的主要组成部分。这主要是由金属线宽缩小导致电阻增加造成的。随着能够综合时钟树的复杂布图工具的出现,由于其具有单元布局信息,适合综合时钟树,因此有必要在DC中描述时钟树,这样可效仿最终布图的始终延迟和扭曲。
1.1 布图前
由于上述原因,最好在布图前阶段估计时钟树延时和扭曲。可用如下命令实现:
dc_shell > create_clock -period 40 -waveform {0 20} CLK
dc_shell > set_clock_latency 2.5 CLK
dc_shell > set_clock_uncertainty -setup 0.5 -hold 0.5 CLK
dc_shell > set_clock_transition 0.1 CLK
dc_shell > set_dont_touch_network CLK
dc_shell > set_drive 0 CLK
上例中,指定2.5ns的延迟作为时钟信号CLK的总延迟。此外,set_clock_uncertainty命令近似时钟扭曲。
1.2 布图后
由于用户不需要担心时钟延迟和扭曲,定义布图后时钟相对比较容易,它们是所布的时钟树的品质所决定的。
一些布图工具为DC提供了直接的接口。这为包含时钟树的布线后网表返回DC提供了一个平滑的机制。若这个信息不存在,用户应从布图工具中提取时钟延迟和扭曲信息。
然而,如果将网表导入DC,那么以下命令可用于定义时钟:
dc_shell > create_clock -period 40 -waveform {0 20} CLK
dc_shell > set_propagated_clock CLK
dc_shell > set_clock_uncertainty -setup 0.5 -hold 0.5 CLK
dc_shell > set_dont_touch_network CLK
dc_shell > set_drive 0 CLK
上述例子一般在做好时钟树后使用,使用指定的后端工具(如ICC)进行时钟树综合。由于在网表中插入了时钟树,因此用户传播时钟而不是将其固定为某个值,所以没有set_clock_latency命令,而包含set_propagated_clock命令。由于需要基于时钟树计算时钟网络的输入转换值,set_clock_transition命令也不需要。
1.3 生成的时钟
许多复杂的设计包含内部生成的时钟,其中一个例子就是时钟触发器逻辑,它用于从主时钟源生成不同频率的次级时钟。
对于下图所示的逻辑,模块clk_div中的时钟除法器电路二分频主时钟CLK并生成驱动模块A的分频时钟。主时钟也用于定时模块B并在驱动模块B之前被内容(在模块clk_div中)缓冲。
对于驱动模块B的时钟,通过create_clock命令在顶层CLK输入的时钟对象的赋值是足够的,这是因为clkB连线继承了在主源指定的时钟对象(通过缓冲器)。然而,clkA则不是如此,DC无法通过整个连线传播时钟对象,因为在主源CLK上的时钟对象规范在寄存器停止。为避免这种情况,应在clk_div模块的输出端口为clkA指定时钟对象。可用如下命令为上例指定时钟:
dc_shell > create_clock -period 40 -waveform {0 20} CLK
dc_shell > create_clock -period 40 -waveform {0 20} find(port, "clk_div/clkA")
或者,也可使用created_generated_clock命令来描述时钟,如下所示:
dc_shell > create_generated_clock -name clkA -source CLK -divide_by 2
2. 综合实例
以不动点迭代算法实现的sqrt运算为例。假设输入数据x是32位有符号整数,令其数据表示范围为-1~+1,则0x80000000表示-1,0x7fffffff表示+1,sqrt.v实现了输入值在0~1之间的根号运算。
verilog代码和综合脚本及必要的db文件可以在下面的链接里找到: