STA | 5. SDC是如何炼成的?时钟定义篇 - 附create_generated_clock花式定义方法!

本文深入探讨了STA(静态时序分析)中时钟的定义与生成过程,包括create_clock与create_generated_clock命令的详细解析。文章通过实例展示了不同场景下的时钟定义策略,如分频、相位调整及多时钟共存的处理方法,为读者提供了全面的时钟管理指南。

前面几篇文章分别介绍了,Cell Delay,Net Delay,以及Path Delay。从《STA | 3. 如何做一条合格的Path》一文中可以看出,对于同步数字电路,只要在时序单元的clock pin定义好了时钟,STA工具或引擎就会默认去检查setup/hold time,否则工具不知道如何进行STA分析。由此可见,定义时钟是STA的第一步,也是写SDC的第一步。

定义时钟

从最早的芯片规格定义分解出系统所需要的时钟和频率,以及各个模块需要的时钟和频率。SoC的时钟一般是由PLL产生,然后经过时钟生成电路和分配网络,最终给具体的功能模块使用。一般地,第三方IP供应商都会提供比较成熟的SDC,SoC集成时需稍作修改。对于自研的IP和SoC顶层,设计人员在提供RTL的同时,也需提供一份时钟结构图,一方面是方便撰写SDC,另一方面对后端PnR有针对性的进行CTS也非常有帮助。

时钟结构图分不同的层次,或抽象或具体,看具体的需要了,下面是一颗MCU全局时钟分布的结构图,大家有个认识就可以:

基于详细的时钟结构图,定义时钟的命令有两个:create_clock和create_generated_clock

其中,create_clock命令比较简单易懂,格式如下:

create_clock [-name clock_name] \
    -period period_value \
    [-waveform edge_list] \
    [-add] \
    [source_objects]

create_generated_clock命令解析

create_generated_clock命令格式如下,主要是定义generated clock和master clock的关系:

create_generated_clock [-name clock_name] \
    -source master_pin \
    [-master_clock clock] \
    [-edge edge_list] \
    [-edge_shift shift_list] \
    [-divide_by factor] \
    [-multiply_by factor] \
    [-duty_cycle percent] \
    [-combinational]
    [-invert] \
    [-add] \
    source_objects

create_generated_clock 需要指定源时钟(master clock)的master_pin,在CTS时,默认会去balance这两个时钟(即generated clock 和 master clock),让skew尽可能小。而且在计算generated clock的clock latency时,会把从master clock pin 到generated clock pin之间的delay也考虑在内。在工具中report_timing的时候,通过选项-path_type full_clock_expanded可以将master clock的部分也展开。

report_timing -path_type full_clock
report_timing -path_type full_clock_expanded

需要注意:在使用create_generated_clock时,需要保证电路结构和命令的效果是一致的,否则工具在report_timing时会报错,比如下面的错误(UITE-461),这时就要仔细检查分频电路结构了。

Error: Generated clock 'CLKdiv2 with source pin Udiv/Q' 'rise_edge' is not satisfiable; zero
source latency will be used. (UITE-461)


Error: Generated clock 'CLKdiv2 with source pin Udiv/Q' 'fall_edge' is not satisfiable; zero
source latency will be used. (UITE-461)

简单2分频

先看一个简单的2分频的实际的例子,命令和效果图如下:

create_clock -name SYSCLK \
    -period 2 \
    [get_ports SYSCLK]
 
create_generated_clock -name DIVIDE \
    -source [get_ports SYSCLK] \
    -divide_by 2 \
    [get_pins FF1/Q]

考虑了edge/edge_shift的3分频实例

下面是3分频的实例,-edge选项中{3 5 9}分别表示SYSCLK的第3、5、9个时钟沿(clock edge),也分别对应DIV3B的一个完整时钟周期(上升、下降、上升)的时钟沿时间点。而-edge_shift选项{2.2 2.2 2.2}表示将DIV3B每个时钟沿都往后延迟2.2ns,命令和效果图如下:

create_clock -name SYSCLK \
    -period 2.2 \
    [get_ports SYSCLK]


create_generated_clock -name DIV3B \
    -source [get_ports SYSCLK]  \
    -edges { 3 5 9 } \
    [get_pins U3/Q]


create_generated_clock -name DIV3C \
    -source [get_ports SYSCLK]  \
    -edges { 3 5 9 } \
    -edge_shift {2.2 2.2 2.2} \
    [get_pins U4/QN]

考虑invert/preinvert的实例

create_generated_clock使用-invert/-preinvert选项都表明generated clock与master clock相位相反,但这两个选项的区别是:

  • preinvert : Creates a generated clock based on the inverted sense of the master clock.

  • invert : Creates an inverted generated clock based on the non-inverted sense of the master clock.

命令和效果图如下:

create_generated_clock -name gclk_pos \
-source [get_pins FF1/CLK]  \
-divide_by 2 \
[get_pins FF1/Q]


create_generated_clock -name gclk_neg \
-source [get_pins FF1/CLK] \
-divide_by 2 \
-preinvert \
[get_pins FF1/Q]


create_generated_clock -name glk_inv \
-source [get_pins FF1/CLK] \
-divide_by 2 \
-invert \
[get_pins FF1/Q]

同一点定义多个generated clock

在实际电路中比较常见的情况是,不同的场景下使用不同频率的时钟来驱动电路,如下图所示,同一个时钟,与经过二分频,四分频后的时钟经过MUX输出给电路使用。

这种情况下,需要在UMUX输出点定义三个时钟CLKbypass/CLKdiv2/CLKdiv4,而且这三个时钟在物理上是不能共存的(physically_exclusive),可以考虑使用以下命令来定义时钟:

create_clock -period 10 CLK


create_generated_clock -name CLKbypass \
    -source [get_ports CLK] \
    -master CLK \
    -divide_by 1 \
    -combinational \
    -add \
    UMUX/Y


create_generated_clock -name CLKdiv2 \
    -source FFdiv2/CK \
    -master CLK \
    -divide_by 2 \
    -add \
    UMUX/Y


create_generated_clock -name CLKdiv4 \
    -source FFdiv4/CK \
    -master CLK \
    -divide_by 4 \
    -add \
    UMUX/Y


set_clock_groups -physically_exclusive \
    -group {CLKbypass} \
    -group {CLKdiv2} \
    -group {CLKdiv4}

注意,这种方式定义时钟看似合理,但是容易造成问题,因为在CLK和UMUX/Y之间有三条不同的路径,延迟大小不同,所以在计算timing时,在launch path和capture path上选择的路径会不同,带来悲观的影响,如下图所示,也有可能在计算min_pulse_width时造成假的违例。

在Solvnet上给出了更恰当的处理方式,具体命令如下:

# create parent clock
create_clock -period 10 CLK


# create divide-by-2, divide-by-4 generated clocks
create_generated_clock -name CLKdiv2 -divide_by 2 FFdiv2/Q -source FFdiv2/CK
create_generated_clock -name CLKdiv4 -divide_by 4 FFdiv4/Q -source FFdiv4/CK


# create "MUXed" versions of all clocks arriving at MUX
create_generated_clock -name CLK_mux -combinational UMUX/A -source UMUX/A
create_generated_clock -name CLKdiv2_mux -combinational UMUX/B -source UMUX/B
create_generated_clock -name CLKdiv4_mux -combinational UMUX/C -source UMUX/C


# create divide-by-3 versions of all clocks arriving at FFdiv3
create_generated_clock -name CLK_mux_div3 \
    -divide_by 3 FFdiv3/Q -source FFdiv3/CK -master CLK_mux -add
create_generated_clock -name CLKdiv2_mux_div3 \
    -divide_by 3 FFdiv3/Q -source FFdiv3/CK -master CLKdiv2_mux -add
create_generated_clock -name CLKdiv4_mux_div3 \
    -divide_by 3 FFdiv3/Q -source FFdiv3/CK -master CLKdiv4_mux -add


# apply physical exclusivity to all clock families (generated clocks included)
# which are exclusive due to statically switched MUX
set_clock_groups -physically_exclusive \
    -group {CLK_mux     CLK_mux_div3} \
    -group {CLKdiv2_mux CLKdiv2_mux_div3} \
    -group {CLKdiv4_mux CLKdiv4_mux_div3}
<think>好的,我现在需要帮助用户解决关于如何计算create_generated_clock的divider参数的问题。首先,我需要回顾用户提供的引用内容,尤其是引用[1]、[2]、[5],因为这些部分提到了生成时钟的设定和相关参数。 用户的问题是如何确定divider参数的值,也就是分频系数。根据引用[2],-divide_by选项用于指定生成时钟相对于源时钟的分频比。所以,分频系数应该是源时钟频率除以生成时钟频率的结果。例如,如果源时钟是100MHz,生成时钟是25MHz,那么divide_by应该是4。 接下来,我需要考虑实际应用中的情况。分频通常通过硬件电路实现,比如触发器或计数器。例如,使用一个每两个时钟周期翻转一次的触发器,相当于分频系数是2。引用[1]中提到,生成时钟需要正确定义在源时钟的派生路径上,可能需要使用-combinational选项或者边沿触发方式。 另外,引用[5]强调了正确选择约束指令的重要性,使用create_generated_clock而不是create_clock来确保派生关系明确,便于维护。因此,分频参数的计算必须准确,以避免时序分析错误。 可能的步骤包括:确定源时钟频率,明确生成时钟的需求频率,计算分频比,并考虑硬件实现方式(如边沿触发或计数器)。同时,需要注意是否还有其他参数如倍频或占空比调整,这些可能需要结合-divide_by和-multiply_by一起使用,例如PLL生成时钟的情况。 还需要提醒用户检查硬件设计,确认分频电路的实际行为,避免遗漏生成时钟约束导致未约束的寄存器。例如,如果使用计数器分频,分频系数等于计数器的模值。此外,如果生成时钟是通过组合逻辑生成的,可能需要使用-combinational选项,但此时分频系数应为1,如引用[1]中的例子。 最后,应举例说明不同情况下的分频参数计算,比如直接分频、PLL配置等,并指出常见错误,如忽略实际电路或忘记使用-add选项处理多生成时钟的情况。</think>在时钟约束中计算$create\_generated\_clock$的$divide\_by$参数值需遵循以下步骤: ### 1. 基础分频计算 **分频系数公式**: $$ divide\_by = \frac{f_{source}}{f_{generated}} $$ 其中$f_{source}$是源时钟频率,$f_{generated}$是生成时钟频率。例如源时钟100MHz需要生成25MHz时钟时: $$ divide\_by = \frac{100}{25} = 4 $$ ### 2. 硬件实现验证 需结合电路实现方式确定分频系数: - **触发器级联**:若使用2个D触发器级联实现4分频,需设定$divide\_by=4$ - **计数器分频**:若计数器每N个周期输出脉冲,则$divide\_by=N$ ### 3. 组合逻辑特例 当使用组合电路生成时钟时: - 若采用$combinational$选项,则强制$divide\_by=1$,此时生成时钟周期与源时钟相同[^1] ### 4. PLL/MMCM配置 在PLL时钟生成场景中: $$divide\_by = PLL\_DIV\_PARAM \times \frac{multiply\_by}{源时钟分频系数}$$ 需同时考虑PLL的倍频($multiply\_by$)和分频参数配置[^3] ### 5. 边沿触发方式 使用$edges$参数时: $$ divide\_by = \frac{边沿列表长度}{2} $$ 例如$edges\ [1\ 3\ 5]$对应3分频(每3个源时钟周期生成1个完整周期) ### 示例配置 ```tcl # 直接分频示例 create_generated_clock -name CLKDIV2 -source [get_pins PLL/CLKOUT] \ -divide_by 2 [get_pins DIV2/Q] # PLL分频示例 create_generated_clock -name CLKOUT -source [get_pins PLL/CLKIN] \ -multiply_by 4 -divide_by 3 [get_pins PLL/CLKOUT] ``` ### 常见错误 1. 未考虑硬件实际分频电路导致约束不匹配 2. 混合使用$divide\_by$和$edges$参数造成冲突 3. 多生成时钟场景遗漏$-add$选项[^1] 4. 误用$create\_clock$代替$create\_generated\_clock$[^5] 需特别注意:时序分析工具会严格验证时钟约束与电路行为的匹配性,建议通过静态时序分析(STA)报告检查实际时钟周期是否符合预期[^4]。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值