Vivado使用技巧(33):时序异常

时序异常
英文名为Timing Exception,可以认为是时序例外或时序异常(本系列文章 的称法),“例外”或“异常”是指这部分时序的分析与大多数常规时序分析不同。下表给出了Vivado支持的时序异常命令及功能:

Vivado不支持即时分析有矛盾的时序异常,需要运行report_exceptions进行完整的分析,报告所有时序异常。多周期路径的情况有很多,比较复杂,单独放在第35篇中讲述。本文介绍其余三种时序异常的相关知识。

虚假路径false path
某些在拓扑结构上看存在于设计中的路径,但是没有工作或者不需要被计时,便被称作虚假路径。虚假路径在时序分析过程中应该被忽略不计。下面这些情况都属于虚假路径:

  • 在有双同步器逻辑的地方有时钟域交叉
  • 可能只在上电时写入一次的寄存器
  • 复位或测试逻辑
  • 异步分布式RAM的写端口于异步读时钟之间的路径
  • 举个具体的例子加深对虚假路径的理解,如下图:

    两个多路选择器MUX控制两个寄存器间的数据传输,但是两个MUX采用同一个选择信号。仔细分析会发现,无论如何Q端数据都无法传递到D端。虽然结构图上看起来Q和D之间存在一条路径,但是没有起到任何功能,因此应该定义为虚假路径。

    为何要在时序分析中移除掉虚假路径?理由如下:

  • 减少运行时间:工具不需要为这些虚假路径计时和做优化,可以减少很多运行时间。
  • 增加结果质量:移除虚假路径可以极大增加结果质量QOR(Quality of Results)。综合、布局和优化设计的质量很大程度上受到时序问题的影响,因为工具总会尝试解决这些问题,包含虚假路径会导致不理想的结果(比如工具将过多注意力放在解决虚假路径的时序违背上,而忽视了真正需要解决的问题)。
  • 虚假路径由set_false_path命令定义,该命令模板如下:
    set_false_path [-setup] [-hold] [-from ] [-to ] [-through ]

    几个节点列表选项的含义如下:

  • -from:一组合法的起点列表,包括时钟对象、时序元素的时钟管脚、输入主端口或双向主端口。
  • -to:一组合法的终点列表,包括时钟对象、时序元素的数据输入管脚、输出主端口或双向主端口。
  • -through:一组合法的管脚或端口,注意节点的顺序很重要。如果约束中仅使用了-through,没有使用-from和-to选项,Vivado会从时序分析中移除所有通过该列表的路径,使用时要特别小心。
  • 下面给出几个定义虚假路径的例子:
    #-through的顺序表示路径穿过节点的顺序,因此下面是两条不同的约束
    set_false_path -through cell1/pin1 -through cell2/pin2
    set_false_path -through cell2/pin2 -through cell1/pin1

    #上图中的虚假路径应该用下面这条命令约束
    set_false_path -through [get_pins MUX1/a0] -through [get_pins MUX2/a1]
    #使用-through而不用-from和-to的好处是可以确保所有通过此节点的路径都会被移除,而不用考虑起点和终点

    #移除复位端口到所有寄存器间的时序路径
    set_false_path -from [get_port reset] -to [all_registers]

    #禁用两个异步时钟域间的时序路径,从CLKA到CLKB
    set_false_path -from [get_clocks CLKA] -to [get_clocks CLKB]
    #注意,上述命令并没有禁用从CLKB到CLKA的路径,还需要补充如下约束
    set_false_path -from [get_clocks CLKB] -to [get_clocks CLKA]

    从最后一个例子可知,我们需要双向地禁用时序路径,但是如果设计中有多个异步时钟域,编写起来就非常麻烦。不知道您是否还记得第31篇中讲过的时钟约束方法,这种情况最好其实应该使用set_clock_groups设置不同的异步时钟组。

    上面还说到了异步分布式RAM的情况,这里也举一个约束例子。假设一个异步双口分布式RAM,其写操作于RAM时钟同步,但是读操作是异步的,这种情况下应该在写和读时钟间设置一个虚假路径。约束如下:

    #在RAM前的写寄存器和RAM后的读寄存器间设置虚假路径
    set_false_path -from [get_cells ] -to [get_cells ]

    个例分析
    设计中,某些信号在特定模式中为常数值,比如:(1).某些测试信号不会变换,直接连接在VSS或VDD上;(2).某些信号上电后便不再发生变化;(3).如果设计有多种功能模式,某些信号在部分模式下为活跃状态,但在其它模式下为不活跃状态。这些情况便属于“个例分析”。

    我们必须告诉静态时序分析引擎,哪些信号为常数值,从而减少分析范围、运行时间和内部占用率,并且不必报告那些不工作的和不相关的路径。通常,设计者使用set_case_analysis命令将信号(管脚和端口)申明为不活跃状态。该命令的语法如下 :
    set_case_analysis

    参数值value可以是0、1、zero、one、rise、rising、fall或falling。作用对象可以是端口(port)、子单元(英文名为leaf cell)的管脚或层次模块的管脚。下面举两个例子加强对这种时序异常的理解。

    第一个例子如下图,clock_sel是一个时钟选择器,通过选择管脚s对两个输入时钟clk_1和clk_2进行选择输出:

    如果我们只希望分析一种个例,比如只分析选择clk_2时的情况。通过将 s管脚设置为常数即可只把clk_2传递到输出端口o。约束如下:
    set_clock -name -clk_1 -period 10.0 [get_pins clock_sel/I0]
    set_clock -name -clk_2 -period 15.0 [get_pins clock_sel/I1]
    set_case_analysis 1 {get_pins clock_sel/S}

    对某一管脚设置了个例分析,会导致禁用经过该管脚的路径上的时序分析,也不会报告相关信息。第二个例子如下图,BUFG_GT有一个动态时钟分频控制管脚DIV[2:0],由其它逻辑驱动而不是直接连接到VCC/GND:

    默认情况下,Vivado会假设输出时钟的最坏可能情况,即1分频(相当于不分频,此时频率最高)。然而如果设计中根本不会出现DIV取1的情况,这就成了过度约束。为了更合理地约束设计,我们可以对DIV[2:0]总线进行个例分析约束,比如可能出现的最差情况为DIV取3,约束如下:
    set_case_analysis 0 {get_pins bufg_gt_pclk/DIV[0]}
    set_case_analysis 1 {get_pins bufg_gt_pclk/DIV[1]}
    set_case_analysis 0 {get_pins bufg_gt_pclk/DIV[2]}

    最小/最大延迟
    最大延迟约束set_max_delay用于改写路径的默认建立时间(或恢复时间)需求;最小延迟约束set_min_delay用于改写路径的默认保持时间(或移除时间)。两条约束命令的语法模板如下:
    set_max_delay [-datapath_only] [-from ] [-to ] [-through ]
    set_min_delay [-from ] [-to ] [-through ]

    -from、-to和-through和虚假路径中的用法相同。set_max_delay命令中如果添加了-datapath_only,那么计算裕量时便不会考虑时钟斜率。使用最小/最大延迟约束要注意如下三点:

  • 路径上仅设置最大延迟约束(不使用-datapath_only选项),不会修改该路径上的最小延迟需求,保持时间检查仍采用默认值,相反也成立。但如果加入了-datapath_only,就会导致该路径上的保持时间需求被忽略。
  • 通常输入端口到第一级寄存器间的约束用set_input_delay命令;最后一级寄存器到输出端口之间的约束用set_output_delay命令(详情见第32篇)。但输入端口到输出端口之间的纯组合逻辑路径可以用set_max_delay和set_min_delay命令进行约束(通常称为in-to-out I/O路径)。
  • 某些异步信号间没有时钟关系,但是需要最大延迟约束。比如我们通常用set_clock_groups划分两个异步时钟域,但有时我们需要确保两个时钟域之间的路径延迟不要太高。这种情况下,我们就要用set_max_delay和set_false_path的命令组合(因为set_clock_groups的优先级更高,会取代set_max_delay,因此不能和其一块使用)。
  • 另外在约束最小延迟和最大延迟时,如果-from和-to中的节点选择不合理,会出现路径分割(Path Segmentation)现象。第34篇给出了路径分割的具体实例及说明。

    禁用Timing Arcs
    最后再介绍一种时序异常的特例:Timing Arcs,字面翻译为时序弧,之所以没有单独列为一种时序异常,是因为它与其它时序异常有着千丝万缕的关系。其实很多情况下计时器为了处理一些特殊情况会自动禁用某些时序弧,比如:

  • 组合逻辑反馈环不能被正确地计时(因此也不推荐使用),计时器会通过禁用环内的某条时序弧来打破环路。
  • 据前文所述,默认情况下MUX的所有输入数据都会传递端口,但是个例分析时将MUX的选择信号设为常数值,此时仅有一个数据输入端口会传递到输出端口。其实这正是由计时器打断了其它数据端口到输出端口间的时序弧实现的。
  • Vivado提供了set_disable_timing命令,可以人为打断一个单元输入端口到输出端口之间的时序弧。考虑如下应用情况:

  • 比如对于上面第一个例子的情况,可以人工设定打断组合反馈环中的哪条时序弧,而不是让工具自动完成。
  • 假设有多个时钟同时到达LUT的输入管脚,但是只能有一个时钟传递到LUT的输出端口。此时需要打断与其它时钟相关的时序弧。
  • 当禁用了时序弧后,通过该时序弧的所有时序路径都不会在时序分析中报告。因此使用时要额外小心,避免禁用了必要的时序弧,导致隐藏的时序违背或时序问题使设计在硬件中不能正常工作。set_disable_timing的语法及示例如下:

    #语法,-from和-to只能设置为库单元的管脚名称(不是设计管脚名称)
    set_disable_timing [-from ] [-to ] [-quiet] [-verbose]

    #禁用所有基于LUTRAM的异步FIFO的WCLK到O之间的时序弧 set_disable_timing -from WCLK -to O [get_cells inst_fifo_gen/ gdm.dm/gpr1.dout_i_reg[*]] #指定对象的所有以O管脚为终点的时序弧都被禁用 set_disable_timing -to O #指定对象的所有以WCLK管脚为起点的时序弧都被禁用 set_disable_timing -from WCLK #指定对象内的所有时序弧都被禁用 set_disable_timing 使用report_disable_timing命令可以查看所有自动禁用和手动禁用了的时序弧。注意这个列表可能会非常大,最好加上-file选项保存结果到文件中查看。

    文章来源:FPGADesigner的博客
    *本文由作者授权转发,如需转载请联系作者本人

    推荐阅读