通常RTL设计要求对芯片/module的输入信号进行reg_in打拍处理,对芯片/module的输出也要求做reg_out打拍处理,这是良好的代码习惯,为时序收敛留下足够裕量,也避免顶层例化综合后的子模块时出现模块间IO时序不满足的情况。综合阶段可根据设计、工艺需求,设置IO的input/output为时钟周期的40%-60%。
但是,芯片timing sign off阶段会偶尔遇到IO时序少量违例,比如,输入reg的hold违例、输出reg的setup违例,本质原因是EDA时序分析工具会在输出输入外部假定一个理想化的不带clock propagation time的寄存器做时序分析。
比如,在set_propagated_clock命令后,下图左边寄存器的CLK2端就不带clock propagation time,而CLK1(与CLK2同频同相)就带insertion delay, 拥有时钟latency,这样输入IO的hold违例就可能发生,setup反而更容易满足。
同理,在set_propagated_clock命令后,输出IO的setup违例就可能发生,hold反而更容易满足。
以输出IO的register的setup建立时间为例,launch clock的data path上由于存在1.5ns的propagation time/clock latency,发生了时序违例。这是因为外部假定的register是没有propagation time/clock latency。而保持时间则反而容易满足。
虚拟时钟应运而生,那么如何创建虚拟时钟?其有什么好处呢?
create_clock -name vclk -period 10
注意,创建虚拟时钟不用指定clk pin/port。
set_input_delay 8 -clock vclk [get_ports data_in ]
set_output_delay 8 -clock vclk [get_ports data_out]
EDA工具会基于虚拟时钟,根据芯片/模块内部时钟的实际insertion delay评估IO外部假定寄存器的propagation time,这样时序分析就可以规避不必要的“假”违例,当然也可以不指定virtual clock,只是每次分析时序时都需要检查并排除这种“假”违例,影响了工作效率。
在约束set_input_delay/set_output_delay时,可以指定真实时钟CLKP,也可以指定虚拟时钟vCLKP,并且创建与CLKP同频率的虚拟时钟vCLKP时,无需指定时钟端口,参考脚本如下:
set period 5
create_clock -name CLKP -period $period [get_ports CLKP]
create_clock -name vCLKP -period $period
在约束set_input_delay/set_output_delay时,是否使用虚拟时钟在CTS之前是没有区别的,可以认为都是理想时钟,毕竟clock tree还没实际建立,时序评估还不能使用propagated clock。而在CTS之后就有如下需要注意的地方:
1)如果指定的是真实时钟,那么下图中的Virtual flip-flop虚拟寄存器的时钟延迟就被忽略了,或者说该虚拟寄存器会被EDA工具认为是理想模型,不带clock propagated time。
2)如果指定的是虚拟时钟,工具往往可以根据内部真实时钟的平均延迟来估算外部虚拟寄存器的时钟延迟,更加合理。
为了让顶层的时序更容易满足,一般会在IN2REG和REG2OUT过约束,可设置外部延迟为60%的时钟周期,给内部的数据路径留40%的空间。具体根据实际项目需求、设计规格、工艺条件等决定。
另外,set_input_delay要指定-max和-min选项,分别对应setup和hold时序检查,如果只指定其中一个选项或都不指定,那么工具在检查setup和hold时,会使用相同的值。
#参考值为0.6,根据实际情况调整
set_input_delay [expr 0.6*$period] -clock vCLKP [get_ports CIN]