单周期时序约束

  • 时序约束的内容
    • 所有输入逻辑路径(从输入端口开始)
    • 内部(寄存器到寄存器)路径
    • 所有输出路径(结束于输出端口)

image-20250316164127191

  • DC将设计分成时序路径,每个路径都有一个:
    • 起始

      • Input port
      • 触发器或寄存器的时钟引脚
    • 终点
      + output port
      + 顺序设备的任何输入引脚,时钟引脚除外

image-20250316170732484

对时钟进行约束

  • 创建时钟
1
2
# 设置时钟的周期约束
create_clock -period 2 [get_ports clk]

image-20250316174015213

  • 模仿时钟到寄存器的时钟延时,clk到两个触发器的时间是不一样的

image-20250316174144046

image-20250316174328666

表示组合路径的最大延迟只能是1.78,必须将clock的uncertainty考虑进来

1
set_clock_uncertainty -setup 0.14 [get_clocks clk]
  • 设置时钟到达的latency,-source表示外部源时钟的延迟
1
2
set_clock_latency -source -max 3 [get_clocks clk] # source latency 约束
set_clock_latency -max [get_clocks clk] # 默认为1,network latency约束

image-20250316190256799

  • 设置时钟引脚的transaction time

Transition 模拟寄存器时钟引脚上时钟波形的上升和下降时间:

1
set_clock_transition Tt [get_clocks clk]
  • cts(时钟树综合)完成前后的约束对比:

在完成时钟树综合之后,可以适当降低uncertainty的值,因为时钟树综合后,实际的时钟偏斜(skew)和抖动(jitter)更明确,不需要预留太多余量;并且不用设置clock的net latency,直接使用set_propagated_clock命令计算传播时钟延迟没,之前用 set_clock_latency 预估的 network latency 被实际布局布线后的时钟树延迟取代,工具会实际计算从时钟端口到每个寄存器时钟引脚的延迟,不再用预估值;不再需要 set_clock_transition(因为实际时钟树会给出更精确的转换时间)

image-20250316190957636

对输入/输出进行约束

image-20250316191322942

  • set_input_delay

set_input_delay约束的是图中箭头部分的延时,用一个周期减去这段就可以得到N部分组合逻辑所需的约束值

1
set_input_delay -max 0.8 -clock clk [get_ports A]
  • 多输入/输出的约束,做相同的约束

image-20250316192652125

对于输入延迟约束,需要排除输入的时钟

1
set_input_delay -max 0.5 -clock CLK [remove_from_collection [all_inputs] [get_ports CLK]]
  • set_output_delay
1
set_output_delay -max 1.1 -clock CLK [all_outputs]
  • 不同ports的约束

实际的约束结果,A、B为0.5,C为0.8,CLK没有约束
后面的约束会覆盖前面的约束

1
2
3
set_input_delay -max 0.5 -clock CLK [all_inputs] 
set_input_delay -max 0.8 -clock CLK [get_ports C] # 会对前面的约束进行覆盖
remove_input_delay [get_ports CLK] # 时钟是不需要进行约束的
  • 约束组合路径

image-20250316204447358

通过下面这些约束,首先时钟周期为2ns,setup要求为0.1ns,input_delay为0.4ns,output_delay为0.2ns,那么组合路径所允许的最大时间延迟为:2-0.1-0.4-0.2=1.3ns

1
2
3
4
create_clock -period 2 [get_ports CLK]
set_clock_uncertainty -setup 0.3 [get_clocks CLK]
set_input_delay -max 0.4 -clock CLK [get_ports B]
set_output_delay -max 0.2 -clock CLK [get_ports D]
  • 约束纯组合设计(创建虚拟时钟)

image-20250316204857435

1
create_clock -name VCLK -period 2
  • Time Budgeting 1/2

image-20250317173352868

image-20250317175924260

保守预算:?和N大约为40%

image-20250318130425861

1
2
3
4
5
# 对上面进行约束的例子
create_clock -period 10 [get_ports CLK]
set_input_delay -max 6 -clock CLK [all_inputs]
remove_input_delay [get_ports CLK]
set_output_delay -max 6 -clock CLK [all_outputs]
  • 寄存器输出

image-20250318130824095

对于input_delay,最大延迟就是从clk到q的最大延迟,即$clk_to_q_max,对于output_delay,最大的延迟就是时钟周期减去clk到q的最小延迟,即10-$clk_to_q_min

1
2
3
4
5
set clk_to_q_max 1.5
set clk_to_q_min 0.9
set all_in_ex_clk [remove_from_collection [all_inputs] [get_ports CLK]]
set_input_delay -max $clk_to_q_max -clock CLK $all_in_ex_clk
set_output_delay -max [expr 10-$clk_to_q_min] -clock CLK [all_outputs] # expr是tcl语言中的计算表达式的关键字

单周期约束扩展

  • 创建时钟,定义占空比

image-20250321151549987

1
create_clock -period 2 -wave_form {0,0.6} [get_ports CLK]
  • 创建时钟,初始的相位偏移(会带来额外的影响,不建议使用)

大多数综合、STA 工具默认期望时钟的第一个上升沿在时间0,使用-wave_form {0.4 1.4}

  • 时钟源点(source latency)会引入一个隐含的偏移
  • 与其他同步时钟的相位关系变得不直观

使用set_clock_latency更好

image-20250321151603963

1
create_clock -period 2 -wave_form {0.4,1.4} [get_ports CLK]
  • 创建更复杂的时钟

image-20250321151835755

对应的时钟波形:

image-20250321151901515

上面触发器的时序约束,默认从clk到d选择时间短的,即0.6ns

  • 下降沿时钟的input_delay约束

image-20250321152809960

1
2
create_clokc -period 2 [get_ports CLK]
set_input_delay -max 0.3 -clock CLK -clock_fall [get_ports A]

对应M逻辑可用的时间:

image-20250321153003672

  • 多输入路径的input_delay约束

image-20250321153124758

1
2
3
create_clock -period 2 [get_ports CLK]
set_input_delay -max 0.3 -clock CLK -clock_fall [get_ports A]
set_input_delay -max 1.2 -clock CLK -add_delay [get_ports A]

告诉dc有两条约束,选择约束更紧的作为具体的input_delay约束条件,如果没有-add_delay选项,默认选择下面这条约束指令

  • 设置驱动单元

image-20250321153938787

1
2
set_input_delay -max 0.6 -clock CLK [get_ports A]
set_driving_cell -lib_cell NAND2_3 [get_ports A]

在input_delay的基础上会再额外增加一个延时,从下面这张图中可以看出,额外增加了0.12ns的延迟

image-20250321154050073

  1. 在具体的设置中是要基于零负载来进行的
  2. set_driving_cell_gate匹配对应的驱动器

例如:有下面三个条件:

  1. 当50pf负载时,0.6ns
  2. 当0负载时,0.48ns
  3. Driving cell on input port A: Qin pin of FD1 flip-flop

对应的约束如下

1
2
3
create_clock -period 4 [get_ports CLK]
set_input_delay -max 0.48 -clock CLK [get_ports A]
set_driving_cell -lib_cell FD1 -pin Qn [get_ports A]
  • 复杂输出路径的约束

image-20250321175927186

最大延迟需要加上setup time,因此时钟上升沿的delay是2.4+0.1=2.5ns
对于时钟下降沿的部分,max ouput_delay为0.6+0.1=0.7ns

1
2
3
create_clock -period 4 [get_ports CLK]
set_output_delay -max 2.5 -clock CLK [get_ports B]
set_output_delay -max 0.7 -clock CLK -add_delay -clock_fall [get_ports B]
  • 默认外部时钟延迟

image-20250321180318379

复杂时序约束和异常

同步多时钟

  • 同步时钟和异步时钟的概念

当两个时钟间的相位是固定关系的,则可以称这两个时钟为同步时钟(synchronous clock)。一般同源,如由同一个MMCM or PLL产生的两个时钟可以称为同步时钟。因此可以将主时钟和与之对应的衍生时钟约束成同一个时钟组。
无法判定两个时钟间相位时,则可以称这两个时钟为异步时钟(asynchronous clocks)。两个来自不同晶振的时钟,一定是异步时钟。通常情况下设计中不同的主时钟肯定是异步时钟,因此可以将这两个主时钟及其衍生时钟约束成不同的时钟组

  • 多时钟input_delay

image-20250322123607698

1
2
3
create_clock -period 3.0 -name CLKA # 虚拟时钟
create_clock -period 2.0 [get_ports CLKC]
set_input_delay 0.55 -clock CLKA -max [get_ports IN1]

上面约束的两个时钟,dc默认是同步时钟

image-20250322122323449

查找两个时钟的上升沿,选择两个上升沿更短的来进行计算
查看波形图,两个上升沿差距更短的是1ns

那么TN应该满足什么条件呢?应该满足的关系如下所示

TN<10.50.05TsetupT_N < 1 - 0.5 - 0.05 - T_{setup}

  • 多时钟的output_delay

image-20250322123825779

1
2
3
4
5
create_clock -period [expr 1000/750] -name CLKD
create_clock -period 1.0 -name CLKE
create_clock -period 2.0 [get_ports CLKC]
set_output_delay -max 0.15 -clock CLKD [get_ports OUT1]
set_output_delay -max 0.52 -clock CLDE -add_delay [get_ports OUT1]

image-20250322124552701

同样需要查找两个上升沿约束更短的部分,分别查找时钟C和时钟D和E短的时间间隔
分别是0.67ns和1ns,Ts对于两条约束等效要求的延迟如下,应该选择约束更紧的作为具体的sdc

Ts<10.55=0.48  and  Ts<0.670.15=0.52T_s<1-0.55=0.48~~and~~T_s<0.67-0.15=0.52

  • 时钟间的不确定度

image-20250322125059315

1
2
3
4
5
create_clock -period 3 [get_ports CLK1]
create_clock -period 2 [get_ports CLK2]
set_clock_uncertainty -setup 0.1 [get_clocks CLK1]
set_clock_uncertainty -setup 0.1 [get_clocks CLK2]
set_clock_uncertainty -setup 0.15 -from [get_clocks CLK1] -to [get_clocks CLK2]

上述的最后一条约束反映了两个时钟之间的偏移

image-20250322125401448

  • Generated clocks

image-20250322125701669

对于二分频电路:

1
create_generated_clock -divide_by 2 -name CK -source [get_ports CLK] [get_pins FFT1/Q]
  • 逻辑上互斥的时钟约束

image-20250322130447414

在选择器的作用下,只会选择一条路径,紫色或者蓝色的路径

1
2
3
4
5
6
7
8
9
create_clock -period 2 [get_ports CLK1]
create_clock -period [expr 1000/750] [get_ports CLK2]
set_output_delay -max 0.15 -clock CLK1 [get_ports out]
set_output_delay -max 0.52 -clock -add_delay [get_ports out]
# 加上伪路径或者逻辑互斥
set_false_path -from [get_clocks CLK1] -to [get_clocks CLK2]
set_false_path -from [get_clocks CLK2] -to [get_clocks CLK1]
# 或者使用逻辑互斥
set_clock_group -logically_exclusive -group CLK1 -group CLK2
  • 部分逻辑上互斥的时钟约束

和上面不同的是CLK1和CLK2的逻辑在前面部分存在交互

image-20250322131321133

1
2
3
4
5
6
create_clock -period 2 [get_ports CLK1]
create_clock -period [expr 1000/750] [get_ports CLK2]
set_output_delay -max 0.15 -clock CLK1 [get_ports out]
set_output_delay -max 0.52 -clock -add_delay [get_ports out]
set_false_path -from [get_clocks CLK1] -through [get_ports out] -to [get_ports CLK2]
set_false_path -from [get_clocks CLK2] -through [get_ports out] -to [get_ports CLK1]
  • 工作时钟选择约束

image-20250322131657397

如果不进行约束,DC优化的路径包括,CLK1 -> CLK1 , CLK1 -> CLK2 , CLK2 -> CLK1 , CLK2 -> CLK2

但是实际上的只有相同的时钟之间的路径,设置的约束如下

1
2
set_app_var timing_enable_multiple_clocks_per_reg true # 允许寄存器有多个clk
set_clock_groups -logic_exclusive -group CLK1 -group CLK2

异步时钟

  • 异步时钟组约束

image-20250322132424178

CLK1和CLK2是异步时钟,设置的约束如下所示:

1
2
3
create_clock -period 3 [get_ports CLK1]
create_clock -period 2 [get_ports CLK2]
set_clock_groups -asynchronous -gropp CLK1 -group CLK2

多周期路径

image-20250322132722207

例如最上面的加法器需要6个时钟周期,需要补充的是不仅仅是DC的约束,在实际的RTL代码中也要保证在6个周期后再进行采样,一般需要一个单独的控制电路

1
2
create_clock -period [get_ports CLK]
set_multicycle_path -setup 6 -from {A_reg[*] B_reg[*]} -to C_reg[*]

上述的约束并不完整,也要保证hold time满足,在最开始和计算完成之后周期的hold time满足就可以

1
set_multicycle_path -hold 5 -from {A_reg[*] B_reg[*]} -to C_reg[*]