sdc:基本的时序路径约束


本文整理自: 数字IC之路-SDC篇(一)

sdc:基本的时序路径约束

1、概念

时序路径

信号可以连续穿过,不必等待其他触发条件的路径。沿着时序路径,信号仅仅在通过电路元器件时有延时。

时序路径是一个点到点的数据通路,数据沿着时序路径进行传输。每条时序路径有一个起点(startpoint)和一个终点(endpoint)

起点定义

  • 输入端口
  • 触发器或寄存器的时钟引脚

终点定义

  • 时序器件的除时钟引脚外的所有输入引脚
  • 输出端口

时序路径类型

  • 输入端口到寄存器(A -> FF1/D)
  • 寄存器到寄存器 ( FF1/clk -> FF2/D)
  • 寄存器到输出端口 ( FF2/clk -> Z)
  • 输入端口到输出端口 ( A -> Z )

在这里插入图片描述

关键路径

路径都存在延时,延时最长的一条路径称为关键路径。一般路径4比较少见

路径约束

1、路径2(寄存器到寄存器的路径)约束

在这里插入图片描述为什么要约束时序路径?

  • 为了满足寄存器的建立时间和保持时间

路径2的时序路径延时:触发器的翻转时间/转换延时、寄存器与寄存器之间的组合逻辑延时、连线延时等

要满足FF2建立时间的要求

需满足:时序路径延时+FF2的setup time,要小于时钟周期。

当对时钟进行建模(即对寄存器与寄存器之间的路径进行约束),时钟周期、时序路径延时就确定了,DC就会选择合适的单元来满足这些延时的约束。若选择最合适的单元,电路的延时还是很大,无法满足FF2建立时间的要求,DC就会报错,发生setup violation。

要满足FF3保持时间的要求

需满足:时序路径延时 ≥ FF2的保持时间(保证FF1的数据传输到FF2时,FF2的前一时刻的数据已经捕获到,不会被覆盖导致出错)

保持时间的分析比建立时间的分析提前一个时钟边沿建立时间是在下一个时钟沿到来时约束,保持时间是在这个时钟沿下第一个触发器的数据不会太快传输到第二个触发器,使得第二个触发器的数据维持时间太短,没有被采样到)

保持时间一般能够满足,若不满足,在后端版图设计的时候修改:加buffer增大延时

create_clock -period 10 [get_ports clk]
# 定义时钟(虚拟时钟后面详述)必须定义周期 period 和时钟源(端口或引脚,上面的clk)
# 可选项:duty cycle(占空比),offset/skew(偏移),clock name(时钟名)

# 查看所定义的时钟属性
report_clock

约束寄存器到寄存器之间的路径,还要添加偏移(skew)、抖动(jitter)、转换时间(transition)、延时(latency)

2、路径1(输入到寄存器D端)的约束

前提:模块前后使用的同一个时钟CLK

在这里插入图片描述

在这里插入图片描述

要满足时序要求,即要求:Tclk - (Tclk-q+Tm) ≥ Tn + Tsetup (即建立时间裕量要≥0)

示例

在这里插入图片描述

在这里插入图片描述

如果已知外部电路的延迟(假设为4),则可约束内部组合逻辑电路允许的最大延时

create_clock -period 20 [get_ports Clk]
set_input_delay -max 7.4 -clock CLK [get_ports A]

即组合逻辑N允许的最大延迟为:20 - 7.4 - 1(setup time) = 11.6ns

反之也可以通过确定内部组合逻辑N的延迟,推出外部输入的最大延时

当有clock skew 和 clock jitter 的时候

假设不确定时间为Tuncertainty,触发器U1的建立时间Tsetup,外部输入延时Texternal_delay(包括前级寄存器翻转和组合逻辑的延时),则N逻辑允许的最大延迟 Tinternal_delay 为:

Tinternal_delay = Tclk_period - Tuncertainty - Tsetup - Texternal_delay

当输入的组合逻辑有多个输入端口时

在这里插入图片描述

对时钟以外的所有输入端口设置约束

set_input_dealy 3.5 -clock Clk -max [remove_from_collection [all_inputs][get_ports Clk]]

# 从所有的输入端口中除掉时钟Clk
#remove_from_collection [all_inputs][get_ports Clk]

# 若要移除多个时钟
remove_from_collection [all_inputs][get_ports "Clk1 Clk2"]

3、路径3(寄存器到输出端口)的约束

在这里插入图片描述

在这里插入图片描述

clk时钟上升沿通过内部电路的寄存器FF2发送数据经过要综合的电路S,再经过输出口B 在下一个时钟的上升沿被到达外部寄存器的FF3接收.

要约束组合逻辑S的延时,则要告诉DC外部输出延时

示例

在这里插入图片描述

在这里插入图片描述

create_clock -period 20 [get_ports Clk]
set_output_delay -max 7 -clock Clk [get_ports B]

若U3的Tclk-q=1ns,则S逻辑允许的最大延时为:20 - 7 - 1 = 12ns

考虑 skew 和 jitter

内部延时S(包括 clk-q 和 组合逻辑延时),外部输出延时X(包括外部组合逻辑和后一级寄存器的建立时间),时钟周期T,uncertainty时间为Y,则

X = T - Y - S

实际SOC设计

各模块分部分设计,需要建立时间预算(Time Budget),为输入、输出端口预置一个商量好的延时

在这里插入图片描述

延时预置规则:

  • DC要求对所有的时间路径做约束,而不应该在综合时还留有未加约束的路径
  • 可以预设输入/输出的内部电路仅仅用了时间周期的40%
  • 若设计中的所有模块都是按照这种假定设置对输入 和 输出进行约束,这还有 20% 时钟周期作为裕量(margin)。裕量包括寄存器FF1的延迟和FF2的建立时间:margin = 20%时钟周期 - Tclk-q - Tsetup

示例

在这里插入图片描述

# contrains
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]

4、路径4(输入到输出)的约束

路径4是组合逻辑的路径,组合逻辑的约束可能需要虚拟时钟。有两种情况

(1)路径4:输入到输出

模块输入到输出端口,有组合逻辑,也有时序逻辑。可以对路径4进行约束

在这里插入图片描述

组合逻辑F的延时:Tf = T - Tinput_delay - Toutput_delay (时钟周期减去两端延时)

set_input_delay 0.4 -clock CLK -add_delay [get_ports B]
set_output_delay 0.2 -clock CLK -add_delay [get_ports D]
set_max_delay $CLK_PERIOD -from [get_ports B] -to [get_ports D];#这句可有可无

考虑uncertainty

假设F的延时是F,外部输入延时为E(clk-q + 组合逻辑延时),外部输出延时为 G (组合逻辑延时 + 后级寄存器建立时间 ),不确定时间为 U,时间周期为 T(最大频率下):

F = T - G -E - U

(2) 纯组合逻辑,内部没有时钟

述

要用到虚拟时钟

2、实战

在这里插入图片描述

设计(约束)规格书:

时钟定义

在这里插入图片描述

寄存器建立时间定义

在这里插入图片描述

输入输出端口延时定义

在这里插入图片描述

组合逻辑定义

在这里插入图片描述

.synopsys_dc.setup文件,设置DC启动环境

common_setup.tcl

在这里插入图片描述

dc_setup.tcl

在这里插入图片描述

.synopsys_dc.setup

在这里插入图片描述

启动DC,查看 target_library信息

$ dc_shell -topo | tee -i star_report.log
# dc_shell -topo:DC的启动命令
#启动时产生的信息,通过 |tee -i流入 start_report.log 文件中

# 读入库
read_db sc_max.db
# 查看库相关联的工艺库
list_libs
# 查看库信息
redirect -file lib.rpt { report_lib 上面的库文件对应的库名称 }
# redirect 重定向命令
# -file 将命令产生信息保存在文件中
# lib.rpt 是要保存信息的文件
# {} 存放要执行的命令
# 终端读取相应库的单位信息,时序单位为ns,电容单位为pf

书写约束

时钟约束

# 1.频率333.33MHz,周期3ns
create_clock -period 3.0 [get_ports clk]

# 2.时钟源到时钟端口的(最大)延时,即source latency 是0.7ns
set_clock_latency -source -max 0.7 [get_clocks clk]

# 3.时钟端口到寄存器的时钟端口延时,即 network latency 为0.3ns,0.03ns的时钟偏移
set_clock_latency -max 0.3 [get_clocks clk]

# 确立clock_uncertainty
# 4.时钟抖动 0.04ns
# 5.需要为时钟周期保留 0.05ns的建立时间裕量
# 时钟偏移为 ±30ps:可能是前一级数十种往后移动30ps,同时本级时钟往前移 30ps,所以建立时间偏移的不确定因素为 30+30=60ps
# 时钟抖动:前一级的时钟抖动影响不到本级,因此只需要考虑本级的时钟抖动。考虑建立时间 -> 本级时钟往前抖动40ps,即对于建立时间抖动的不确定因素为 40ps
# 建立时间不确定余量:50ps
# 总的不确定时间: 60+40+50=150ps=0.15ns
set_clock_uncertainty -setup 0.15 [get_clock clk]

# 6.时钟转换时间:0.12ns
set_clock_transition 0.12 [get_clocks clk]

输入延迟约束(输入路径约束)

# 1.规定模块内 data1 和 data2 端口的逻辑S延时最大为 2.2ns,没有直接告诉外部逻辑延时
# 外部最大延时:clock_period - clock_uncertainty - delay_of_S - register_setup_time = 3-0.15-2.2-0.2=0.45ns
set_input_delay -max 0.45 -clock clk [get_ports data*]

# 2.规定sel端口从外部数据发送端(F3的clk)到sel端口的latest(最大延时)是1.4ns,包括时钟的latency延时
# input_delay不包括时钟的latency延时,是相对时钟的前级逻辑延时,要减去时钟的latency(包括source和network):1.4ns-(700ps+300ps)=0.4ns
set_input_delay -max 0.4 -clock clk [get_ports sel]

输出延时约束(输入路径约束)

# 1.out1的外部组合逻辑的最大延时为0.42ns,后级触发器的建立时间为 0.08ns,则外部延时 0.42+0.08 = 0.5ns
set_output_delay -max 0.5 -clock clk [get_ports out1]

# 2.out2的内部延时为810ns:时钟周期-内部延时(翻转与内部组合逻辑延时)- 不确定时间=外部延时(外部组合逻辑+后级寄存器的建立时间),即 3-0.81-0.15=2.04ns
set_output_dealy -max 2.04 -clock clk [get_ports out2]

# 3.out3外部延时只有后级寄存器的建立时间要求
set_output_delay -max 0.4 -clock clk [get_ports out3]

组合逻辑约束

根据前面的公式可得:3-0.15-输入延时-2.45=输出延时,即 输入延时+输出延时=0.4ns

若综合后有违规,后面可以适当调整一下

set_input_delay -max 0.3 -clock clk [get_ports Cin*]
set_output_delay -max 0.1 -clock clk [get_ports Cout]

其他流程

  • 启动DC

  • 读入设计

  • 查看设计(check_design)

  • 应用约束和查看约束

    • 应用约束: source scripts/MY_DESIGN.con
    • 查看是否有缺失或冲突的关键约束:check_timging
      • 返回1,表示执行成功
  • 验证时钟是否约束正确

    report_clock
    report_clock -skew
    report_port -verbose
    
  • 保存约束好的时钟

    write -format ddc -hier -out unmapped/MY_DESIGN.ddc
    
  • 综合

  • 综合后检查与优化

  • 保存综合后的设计

详细可查看原文