ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

多周期路径与set_multicycle_path:从原理到时钟域时序收敛实战

多周期路径与set_multicycle_path:从原理到时钟域时序收敛实战 我第一次独立收敛一颗SoC的时序时被一条 slack -5.2ns 的路径卡了整整两天。查路径、插 buffer、调驱动怎么都压不下来。带我的老工程师路过看了一眼问我起点时钟是多少发射域和捕获域之间是什么关系我回答是 100MHz 和它的 2 分频时钟。他说CLK_DIV 每两个 100MHz 周期才上升一次数据明明有两拍可以走你为什么要按单周期让它一个周期内到加一行set_multicycle_path 2 -setup试试。那天之后我才真正理解在静态时序分析里默认假设是“单周期路径”但现实中大量跨时钟、分频、接口场景的数据通路并不是单周期才有效。所以这篇东西我不打算只抄一遍命令手册而是把多周期路径和set_multicycle_path的完整逻辑讲透默认检查怎么来的、命令参数到底在调什么、快慢时钟不同方向该怎么配、最常见的坑在哪里、以及最后怎么确认约束真的按你预期生效了。适合正在做数字后端或刚接手 STA 收敛的工程师也适合前端同学理解为什么后端总在约束文件里“加周期”。1. 单周期检查的“默认偏见”与多周期路径的出生逻辑1.1 一个让新人懵圈的违例报告回到开头那个案例。假设 CLK 是 100MHz周期 10nsCLK_DIV 是 CLK 的 2 分频周期 20ns上升沿分别出现在 CLK 的第 0、2、4……个沿。存在一条数据路径起点寄存器在 CLK_DIV 域终点寄存器在 CLK 域。如果不加任何约束STA 工具会怎么检查这条路径工具默认对所有同步路径做“单周期检查”意思是数据在发射时钟的一个有效沿被送出去必须在捕获时钟的下一个有效沿之前准备好。对于 CLK_DIV 到 CLK 这条路径发射沿是 CLK_DIV 上升沿工具会找它后面最近的 CLK 上升沿作为捕获沿。如果 CLK_DIV 的上升沿恰好和 CLK 上升沿对齐那么下一个 CLK 上升沿可能就在 10ns 之后路径只有 10ns 可用。但真实设计中CLK_DIV 域的数据通常只是在 CLK_DIV 的上升沿附近更新一次CLK 域却每个周期都在采样。如果数据确实需要在 CLK_DIV 后的第一个 CLK 沿就被采到那这就是一条实际可用的单周期路径10ns 就是真实要求但如果数据是经过握手或者协议允许的要等到第二个、第三个 CLK 沿才被采样那 10ns 的检查就是冤枉它了。1.2 默认检查的数学描述与逻辑基础把默认的单周期检查写成公式更清楚。对标准 setup 检查工具比较的是两组时间数据到达时间 发射时钟沿时间 寄存器 CK-to-Q 延时 组合逻辑延时 路径上各种 net 延时数据要求时间 捕获时钟沿时间 - 捕获触发器 setup 时间 - 时钟不确定性uncertainty单周期假设下发射沿和捕获沿之间正好差一个捕获时钟周期。再考虑时钟 skew实际检查的是数据能不能在“发射沿后的第一个捕获沿”之前稳定下来。hold 检查则是另一组数据要求时间 捕获时钟沿时间 捕获触发器 hold 时间 时钟不确定性数据到达时间则要看数据在捕获沿之后还能不能保持稳定。单周期默认下来hold 检查针对的是同一个时钟沿附近的相邻发射沿防止数据变化太快把上一个值冲掉。问题来了如果数据通路真的可以在多个周期内完成单周期检查会把一条本来很宽松的路径压到极限导致大量不必要的 buffer 插入、面积和功耗浪费甚至收敛不了。多周期路径就是用来告诉工具这条路径的有效窗口不是 1 个捕获周期而是 N 个捕获周期。1.3 为什么不是所有路径都适合做多周期有一点必须先说清楚多周期路径不是“我在 STA 里放水”的工具。它是对设计功能的如实描述。只有当下游寄存器确实不会在发射沿后的第 1 个捕获沿采样该数据而是在第 N 个捕获沿才采样时才能设置set_multicycle_path N。判断标准在看 RTL。典型适合做多周期路径的场景包括同步整数分频后的时钟域之间数据更新频率低于采样频率流水线中某一级本来就有多个周期时间预算外部接口协议约定数据在地址/控制信号发出后若干周期才有效低频握手信号数据有效窗口横跨多个时钟周期不适合的场景是异步跨时钟域。异步时钟之间的沿没有确定的对齐关系数“第 N 个沿”没有意义应该用同步器加set_false_path或set_clock_groups。这个区分很多新人会搞混后面专门讲。2. set_multicycle_path 命令的六个关键旋钮2.1 命令长什么样SDC 标准里的set_multicycle_path完整语法很长工程上常用的核心选项就这些set_multicycle_path path_multiplier [-setup | -hold] [-start | -end] [-from startpoints] [-through points] [-to endpoints]path_multiplier必须给的正整数代表相对默认单周期检查的倍数。-setup 2表示 setup 检查沿往后推 1 个周期-setup 3表示往后推 2 个周期。-setup/-hold指定这条约束作用在 setup 还是 hold 检查上。如果不给工具会把同一个值同时作用到 setup 和 hold但实际项目中几乎没人这么干因为这个默认值对 hold 往往不是我们想要的。-start/-end指定在 launch 时钟域计数还是在 capture 时钟域计数默认是-end。这是跨时钟域配置最容易错的地方后面会展开。-from/-through/-to限定路径范围。可以指定时钟、端口、cell 引脚。工程上几乎总是用-from [get_clocks ...] -to [get_clocks ...]限定时钟域之间的所有路径局部路径才用引脚。2.2 最容易被忽略的默认行为setup 和 hold 的联动我见过太多工程师只在约束文件里写了一行set_multicycle_path 2 -setup -from [get_clocks CLK] -to [get_clocks CLK_DIV]然后以为完事了。但这里有个隐含的默认行为当工具看到-setup 2而没有显式-hold时它会自动把 hold 的乘数设为2 - 1 1。也就是说hold 检查也被向后推了一个周期。工具为什么要这样设计因为如果不往后推hold 检查还是按默认沿做而 setup 已经往后推了两个周期数据会被允许在两个周期后才稳定这时如果 hold 还在第一个采样沿检查工具会发现数据在第一个沿附近很可能不满足 hold——但那个沿本来就不是有效采样沿检查它没有意义。为了不让 hold 报告充满无效违例工具自动把 hold 沿也顺延到有效采样沿的前一个沿。问题是这个自动值不一定符合你的设计。很多场景下数据虽然在第二个沿才被捕获但它在发射沿后的第一个采样沿处必须保持稳定不能提前翻转否则会踩到其他并行路径的采样窗口。这时默认的 hold 延后处理会让你漏掉真实风险。所以规范的做法是显式把 hold 也写出来set_multicycle_path 2 -setup -from [get_clocks CLK] -to [get_clocks CLK_DIV] set_multicycle_path 1 -hold -from [get_clocks CLK] -to [get_clocks CLK_DIV]这里 hold 到底写 1 还是 0取决于你希望 hold 检查沿停在哪里。写 1 等价于工具默认的自动行为写 0 表示 hold 仍然在发射沿后的第一个采样沿检查约束更严。先记住结论不要省略 hold省略等于把设计意图交给工具的默认值。2.3 start 和 end到底在哪个时钟域数沿这是set_multicycle_path里最容易搞混的一对选项。默认是-end表示乘数 N 是在捕获时钟域内数出来的。举个例子慢时钟域到快时钟域慢时钟周期 40ns快时钟周期 10ns两者相位对齐。你写set_multicycle_path 4 -setup -end -from [get_clocks SLOW] -to [get_clocks FAST]意思是捕获域FAST的有效采样沿在默认捕获沿的基础上往后数 4 个 FAST 周期。默认捕获沿是慢时钟发射沿后的第一个 FAST 上升沿往后数 4 个 FAST 周期实际就是第 5 个 FAST 上升沿。可是数据明明是慢时钟域发出的慢时钟域 40ns 才发一次你要它等 50ns 才被采设计上通常并不会这么干。这种情况下用-start在发射域数沿更符合直觉。反过来的场景快时钟域到慢时钟域快时钟 10ns慢时钟 40ns。你用默认-end写set_multicycle_path 4 -setup -end -from [get_clocks FAST] -to [get_clocks SLOW]捕获域是 SLOW在慢时钟域数 4 个沿意味着捕获沿要往后推 4 个慢时钟周期也就是 160ns这个预算远大于数据真实可用的时间。而实际上慢时钟域每 4 个快时钟周期才采一次样数据只需要在发射沿后的第 4 个快时钟沿处准备好就够了。所以这里应该用-startset_multicycle_path 4 -setup -start -from [get_clocks FAST] -to [get_clocks SLOW]一句话总结乘数 N 想表达“几个发射域周期”就用-start想表达“几个捕获域周期”就用-end。快到慢的场景数据由快域发射我们说“允许 4 个快时钟周期后到达”自然是在发射域数沿慢到快如果协议允许“慢时钟发出后第 2 个快时钟沿采样”这一个“第 2 个快时钟沿”是在捕获域数出来的用-end是合理的。所以重点不是记口诀而是搞清楚你心里的 N 到底是哪个域的周期。3. 三类典型场景下的约束写法与波形推演3.1 整数分频时钟域之间的路径方向不同约束不同假设 PLL 输出 100MHz 的 CLK通过create_generated_clock -divide_by 2得到 CLK_DIV。两个时钟相位严格对齐CLK_DIV 上升沿出现在 CLK 的偶数沿。工程上最常见的疑问是CLK 和 CLK_DIV 之间的路径到底要不要设多周期先看 CLK 到 CLK_DIV也就是快发射、慢捕获。数据在每个 CLK 沿都可能变化但 CLK_DIV 只在每两个 CLK 沿才采样一次。名义上数据有两个 CLK 周期可以走。不过 STA 工具对 generated clock 的沿关系有一定感知它会分析 launch edge 和 capture edge 的实际距离。问题是发射沿是 CLK 的哪个沿结果会不同发起在 CLK 偶数沿捕获沿可能是 20ns 后发起在 CLK 奇数沿捕获沿可能是 10ns 后。工具默认会挑最紧的组合来报导致部分路径被按 10ns 检查。我习惯显式写清楚set_multicycle_path 2 -setup -start -from [get_clocks CLK] -to [get_clocks CLK_DIV] set_multicycle_path 1 -hold -start -from [get_clocks CLK] -to [get_clocks CLK_DIV]这样工具就明白CLK 域到 CLK_DIV 域的数据允许在两个 CLK 周期后到达而不是拿最紧的组合反复报违例。hold 显式设 1让数据在发射后的第一个 CLK 沿处也满足保持这是安全的选择。再看 CLK_DIV 到 CLK慢发射、快捕获。数据只在 CLK_DIV 上升沿时更新CLK 每个沿都在采样产品功能上如果要求下一个 CLK 沿就采到这个数据那就不能设多周期反而是要防住路径太长必要时靠物理实现去优化。但如果数据更新后钳位/握手逻辑保证 CLK 域在若干周期后才真正使用该数据情况另说。所以分频域之间“到底设不设、设几”必须回到功能和时钟沿相位关系不能笼统一刀切。3.2 快时钟域到慢时钟域在 launch 域数沿的典型场景这是多周期路径最经典的场景。快时钟 FAST 100MHz慢时钟 SLOW 25MHz两个时钟来自同一 PLL相位对齐SLOW 上升沿每 4 个 FAST 周期出现一次。一条数据路径从 FAST 域寄存器发射终点是 SLOW 域寄存器。因为 SLOW 每 4 个 FAST 周期才采一次所以数据其实有 4 个 FAST 周期时间到达。约束写法set_multicycle_path 4 -setup -start -from [get_clocks FAST] -to [get_clocks SLOW] set_multicycle_path 3 -hold -start -from [get_clocks FAST] -to [get_clocks SLOW]为什么要-start因为 4 这个数指的是“数据发出后第 4 个 FAST 沿到达即可”是在发射域数出来的。如果写成-end工具会在 SLOW 域数 4 个沿等于往后推了 4 个慢时钟周期也就是 160ns远大于实际需要的 40ns虽然时序容易过但完全失真一旦设计改动这种约束掩盖下的问题会集中爆发。hold 显式写 3 而不是依赖自动值因为这里我要求数据在发射沿后的第 3 个 FAST 沿处也满足保持要求防止信号翻转过早影响 SLOW 采样沿附近的数据稳定性。实际项目里这个值要根据发射沿与采样沿的对齐关系重新确认我后面会讲到验证方法。3.3 慢时钟域到快时钟域与握手接口捕获域数沿的适用场景慢到快或者两个不同源但频率成整数倍的时钟域之间情况要微妙得多。SLOW 40MHzFAST 80MHzSLOW 的上升沿和某个 FAST 上升沿对齐。数据从 SLOW 域发出FAST 域每个周期都在采样。如果功能上要求数据在 SLOW 沿后的第二个 FAST 沿才被采样例如第一个 FAST 沿用来做同步打拍不采数据那可以用set_multicycle_path 2 -setup -end -from [get_clocks SLOW] -to [get_clocks FAST] set_multicycle_path 1 -hold -end -from [get_clocks SLOW] -to [get_clocks FAST]这里用-end是合理的因为“第二个 FAST 沿”是在捕获域 FAST 里数的。但这种写法成立的前提是 SLOW 和 FAST 存在确定的对齐相位工具能算出第二个 FAST 沿具体在哪。如果两个时钟完全异步那set_multicycle_path本身就不适用应该用同步器加set_false_path。握手接口是另一个常见场景。例如一个外部 SRAM 接口地址在时钟沿发出后数据要等两个周期才从 SRAM 返回路径的终点是一个捕获寄存器但数据有效窗口是第二个周期末。这时可以在接口路径上设set_multicycle_path 2 -setup -from [get_pins u_sram_ctrl/addr_reg/CK] -to [get_pins u_sram_ctrl/data_capture_reg/D] set_multicycle_path 1 -hold -from [get_pins u_sram_ctrl/addr_reg/CK] -to [get_pins u_sram_ctrl/data_capture_reg/D]这里不涉及跨时钟域-start和-end的结果一样但建议还是明确写出来免得后面读约束的人猜。关键不在于参数写得多完整而在于你清楚数据协议给了几个周期预算。4. 快慢时钟搭配时-start/-end 的选型决策与常见错配4.1 一张表看懂怎么选很多人问我有没有快速判断方法。我把工程上最常见的四种组合整理成了表前提是时钟之间存在确定相位关系路径方向周期关系举例setup 建议写法hold 建议写法说明快时钟域 → 慢时钟域FAST 10nsSLOW 40ns-setup N -start-hold N-1 -startN 是快域周期数必须在发射域数沿慢时钟域 → 快时钟域SLOW 40nsFAST 10ns-setup N -end或按设计-hold N-1 -end或更严N 是捕获域沿数默认-end通常可用同频同相同步域两个 10ns 时钟-setup N -end-hold N-1 -end两域周期相同start/end 不影响结果整数分频同步域CLK 10nsCLK_DIV 20ns快→慢用-start慢→快慎重对应调整重点看发射沿与采样沿实际距离表格只能给方向具体 N 值还是要回到电路功能。比如快→慢是 4 倍关系但协议允许数据在 4 个快周期后到达N 就是 4如果协议放宽到 6 个快周期N 就是 6。不要因为时钟倍数是 4 就机械地填 4倍频关系只是“默认最大预算”不是“必须用满的预算”。4.2 错配 -end 会带来什么后果我见过一个项目快时钟 500MHz慢时钟 125MHz路径从快域到慢域。工程师写了set_multicycle_path 4 -setup -end -from [get_clocks FAST] -to [get_clocks SLOW]表面上看4 倍关系乘 4没毛病。但因为用了-end工具在捕获域 SLOW 里数 4 个沿也就是把采样沿从默认对齐沿往后推了 4 个慢时钟周期整整 32ns。而电路真实只需要 8ns。这条路径因此被过度放宽后面 ECO 改了逻辑实际延时涨到了 15nsSTA 仍然报过因为预算被错误地放到了 32ns。流片回来芯片在高温低压条件下偶发采样错误定位到最后就是这条约束把真实时序风险掩盖了。排查时把-end改成-start重新 report_timing路径真实的 15ns 延时立刻暴露实测确实存在 hold 和 setup 双风险。这个教训我一直记着约束写错方向比不写还危险因为它会让 STA 报告失真。4.3 一个容易混淆的局部路径写法除了时钟域到时钟域还可能遇到从某个发射引脚到某个捕获引脚的局部多周期。这时-start/-end的语义不变但要注意-from/-to里指定的是引脚STA 会根据引脚归属的时钟沿来计算。如果两个引脚分属不同时钟域上面的选型规则同样适用如果是同一时钟域内部的一条路径-start和-end结果一致因为发射域和捕获域是同一个时钟。同域内设多周期常见于大规模组合逻辑被有意拆成两个周期完成。例如set_multicycle_path 2 -setup -from [get_pins u_fifo/wr_ptr_reg/Q] -to [get_pins u_fifo/full_logic_reg/D] set_multicycle_path 1 -hold -from [get_pins u_fifo/wr_ptr_reg/Q] -to [get_pins u_fifo/full_logic_reg/D]full 逻辑由于多级比较器链很长设计上允许它两拍后才产生稳定 full 信号。这种约束是合理的但也最容易被人滥用因为“允许两拍”和“实际真的需要两拍”是两回事如果实际 1.2 拍就能完成设置 2 拍只是给了余量这没问题但如果电路本来需要 2.3 拍你设 2 拍STA 必然报违例逼着你去优化逻辑这才是约束应该有的作用。5. 我在多个项目里反复踩过的 multicycle 坑5.1 只设 setup 不设 hold默认值可能毁掉一条路径这是最常见的问题前文已经讲过工具的自动 hold 行为。实际遇到的情况是某条路径 setup 设了 4hold 没写工具自动按 3 处理。后来功能仿真和芯片实测都发现这条路径在发射沿后的第一个采样沿处数据翻转过快导致并行逻辑采样到不确定值。因为 hold 检查被推后STA 根本没有报这条风险。解决方案就是把 hold 显式写出来并且想清楚 hold 检查沿该停在哪。我自己的习惯是除非设计明确要求更宽的 hold 窗口否则在快→慢的场景里hold 用N-1并配合-start在慢→快的场景里hold 至少用0或1视相位关系而定然后通过 report_timing 复核实际沿位置。5.2 把 multicycle 当橡皮擦逻辑功能会替你交学费有些工程师遇到时序违例第一反应是“反正能设多周期就设个 2 拍呗”完全不回去查 RTL 是否允许数据两拍后才有效。这是把 multicycle 当橡皮擦用一时舒服后面芯片出了功能问题查起来比多插几百个 buffer 痛苦得多。我想强调一个判断标准multicycle 约束里的 N必须是设计文档或 RTL 里能翻到的“显式约定”。例如流水线 valid 信号每两拍拉高一次、握手协议规定 data 在 req 拉高后第二个时钟沿才被采样、分频器保证数据更新频率是采样频率的一半。如果这些约定一个都说不出来那这个 N 就只是你为了让 STA 变绿编出来的数字流片风险极高。5.3 混淆多周期路径和异步 false path有工程师看到两个时钟没有确定相位关系直接写set_multicycle_path 2 -setup -from [get_clocks CLK_A] -to [get_clocks CLK_B]异步跨时钟域之间根本没有可数的“第 2 个沿”因为两个时钟沿的相对位置每周期都在变。工具虽然能算出某个对齐假设下的沿但那个假设在芯片实际工作中不成立。正确做法是用两级同步器打拍然后对跨时钟路径设set_false_path或set_clock_groups -asynchronous让工具完全跳过这些路径的时序检查。多周期路径和 false path 的本质区别是多周期路径仍然在查时序只是把检查窗口放宽false path 是完全不查。前者适用于“有确定时钟关系、但有效采样沿推后”的路径后者适用于“不存在有效采样沿”的路径。把异步路径设成多周期等于给一个不存在的采样沿做检查报告既不可信还会掩盖真实问题。5.4 复位释放路径上的误用复位释放时序reset removal / recovery是另一个容易被乱加 multicycle 的地方。复位信号经过同步器后释放时钟域逻辑开始工作这个释放路径要求复位在时钟沿前稳定下来。有些工程师看到 recovery 违例顺手加一个set_multicycle_path 2让释放多一拍表面时序过了但芯片上电后部分触发器可能还在复位状态、部分已经开始工作功能直接错乱。复位释放路径的正确处理是保证复位同步器的输出满足触发器的 recovery/removal 时间通常通过约束复位同步器时钟路径、保证释放沿与时钟沿的相位关系来实现而不是靠放宽检查窗口。遇到 recovery 违例优先看复位同步器结构而不是调 multicycle。5.5 改约束文件后不重新核对捕获沿这个坑更隐蔽。约束文件在项目过程中会被反复修改特别是 ECO 后某些时钟的生成方式变了、分频关系变了但往日的 multicycle 约束还挂在原处。乘数没变可是捕获沿实际位置已经变了导致约束语义和设计完全脱节。我处理过一起案例某模块时钟从 2 分频改成 4 分频旧的set_multicycle_path 2没删新设计下数据有 4 拍时间但工具还在按 2 拍检查优化成本白白增加反过来分频比改小但约束没改又会掩盖真实违例。所以每次改时钟树约束或 RTL 跨时钟逻辑都要把相关的多周期路径全部重新 report 一遍。6. 如何验证一条 multi-cycle 约束真的按预期生效6.1 report_timing 里最该看的三个字段约束写完之后第一件事不是看 slack 是否变绿而是确认检查沿位置。用 report_timing 报一条被约束的路径report_timing -from [get_clocks FAST] -to [get_clocks SLOW] -setup -path_type full report_timing -from [get_clocks FAST] -to [get_clocks SLOW] -hold -path_type full重点看报告里的三个字段Launch Clock Edge数据实际发射沿的时间Capture Clock Edge工具实际用于采样检查的捕获沿时间Path Type显示是 maxsetup还是 minhold例如 FAST 10ns、SLOW 40ns设了-setup 4 -start之后setup 报告的 Capture Clock Edge 应该落在发射沿后的第 4 个 FAST 沿对应的那个 SLOW 沿上而不是默认的第 1 个。如果 Capture Clock Edge 还是默认沿说明约束没写到这条路径上要查-from/-to的集合是否真的覆盖了目标时钟或引脚。用report_timing之前可以先跑一下report_constraints看约束匹配到的路径数量数量为 0 就说明范围写错了。6.2 用check_timing和约束汇总报告交叉验证我还习惯在跑完约束后执行一次约束一致性检查check_timing -verbose重点看两类告警。一类是“unconstrained path”表示某些时钟之间存在路径但没有约束工具默认按单周期处理另一类是“multicycle path conflicts”表示同一条路径被多条相互矛盾的 multicycle 约束命中工具只能选其中一条生效这往往是约束文件里存在重复定义或层级继承问题。另外用report_timing -nworst 20 -max_paths 20抽查数据路径看是不是所有在预期范围内的路径都挂上了正确的 Capture Clock Edge。多周期约束最大的特点是“沉默生效”约束写错了工具不报 error只会按照错误语义报一个貌似正常的数字。所以交叉验证这一步绝对不能省。6.3 结合 VCD 波形核对动态行为STA 只能证明约束语义下路径满足时序不能证明约束语义和功能意图一致。我的做法是找到一条被约束的关键路径在仿真里拉出 VCD用波形工具观察三个时间点发射沿位置数据在终点寄存器 D 端最后翻转的时刻捕获沿位置如果拉出来的波形显示数据在发射沿后 15ns 才稳定而捕获沿在 40ns那条路径的 setup 余量大约 25ns和 STA 报告量级一致。一旦发现波形里数据明明在第 2 个快时钟沿就已经翻转STA 却按第 4 个沿做采样检查那就要重新审视-setup的 N 值是否填大。波形核对不麻烦但对避免“约束过了、功能错了”这种问题非常有效。6.4 流片前的一条固定检查项我负责过的项目在 final signoff 前都有一个固定动作把约束文件里所有set_multicycle_path行导出逐条对照设计文档打勾内容包括路径范围、setup N 值、hold M 值、start/end 方向、设置原因。任何一条答不上来“为什么是这个 N”的约束都视为风险项必须在 tapeout 前解决。用脚本抓取所有 multicycle 约束也很简单SDC 文件里直接 grep 就能看到全貌。拿到清单后对每条路径再跑一次report_timing -setup和report_timing -hold确认 slack 都不是靠异常宽大的捕获沿撑出来的。这个动作看起来繁琐但能拦住大多数约束层面的低级错误。最后分享一个我养成的习惯所有多周期约束我都会在 SDC 里写注释写明为什么是 N 拍、数据协议如何允许这个延迟、hold 为什么选这个值。因为三个季度之后你回头 review 约束文件往往已经忘了当初为什么这么写。set_multicycle_path从来不是一行命令那么简单它是对一条数据通路功能时序的完整表达想清楚了再落笔比事后追着报告查要省力得多。
返回列表