☰
异步SAR逻辑综合后出错?高频原因与排查手段全解析
2026/10/13 1:09:25 网站建设 项目流程

前些天帮某同事排查一颗8位异步SAR控制逻辑的综合问题,RTL仿真跑了成百上千个向量都很正常,结果一到综合后的门级网表仿真,就总在特定输入附近差一两个LSB,偶尔还会把一整段转换序列丢掉。查了快一周才找到根因,其实就藏在一组被综合工具悄悄优化掉的锁存器和一条完全没有任何约束的内部异步路径上。这个排查过程让我又一次确信:只要是异步SAR逻辑电路综合后出错,原因往往比同步设计要隐蔽得多。

异步SAR(逐次逼近寄存器)逻辑电路在低功耗中高精度ADC里已经很常见了,它最大的特点是没有一个全局高频时钟来驱动逐次逼近的每一步,而是靠比较器产生的事件信号(通常叫valid)去触发SAR寄存器更新、DAC开关切换,推进到下一个比较周期。这套事件驱动机制在RTL仿真里看起来非常干净利落,但一旦进入逻辑综合阶段,那些为同步设计准备的工具模型、默认约束和优化策略,几乎处处都在跟你的异步逻辑唱反调。这篇文章我不绕圈子,直接把异步SAR逻辑电路综合后出错的高频原因和对应的排查手段,一条一条说清楚。

1. 为什么偏偏是异步SAR:先看电路结构里埋着哪些"雷"

1.1 一条由事件驱动、没有全局时钟的工作链

在具体讲出错原因之前,有必要先把这个电路的骨架捋一遍。异步SAR的核心思想是:不做全局时钟同步状态机,而是让每个转换周期靠"前一个动作完成"的事件启动"下一个动作"。以典型的N位SAR ADC控制逻辑为例,一条完整的工作链是:

  • 采样阶段:采样开关闭合,把输入电压采样到电容DAC阵列或跟踪保持电路上;
  • 比较阶段:比较器比较DAC当前输出电压与输入电压,输出一个比较结果(cmp_out);
  • 事件产生:比较器输出稳定后,控制逻辑产生一个valid脉冲,表示"本轮比较已完成";
  • SAR更新:valid脉冲触发SAR逻辑,根据cmp_out更新逐次逼近寄存器中的当前位;
  • DAC建立:SAR寄存器更新后,DAC阵列切换到一个新的电压,进入建立过程;
  • 下一轮开始:DAC建立完成后,再次启动比较器开始一次新的比较。

这一圈循环里,valid信号的产生和传递是全局命脉。整个数字控制部分不再像同步电路那样"所有寄存器在时钟边沿同一时刻更新",而是"某事件发生后,特定寄存器才更新"。很多RTL设计者习惯性地把valid写成下面这种风格:

always @(posedge valid or negedge rst_n) begin if (!rst_n) begin sar_code <= 0; end else begin sar_code[BIT_INDEX] <= cmp_out; end end

这种写法在RTL仿真中没有任何问题,因为RTL里的valid是理想脉冲,只有你要它翻转的时候它才翻转。可到了综合后的网表里,valid是实实在在经过若干个逻辑门产生的物理信号,它是否能维持理想的"脉冲宽度""边沿干净度""到达时间",完全取决于综合工具对你那堆异步逻辑做了什么处理。这也就解释了为什么很多问题的第一现场都出现在valid相关的路径上。

1.2 综合工具默认模型与异步逻辑的冲突

再说综合工具这边。主流逻辑综合工具的底层模型几乎都基于同步时序假设:所有寄存器由时钟边沿触发,所有组合路径延迟都在同一个时钟周期内,设计者只需要用时钟周期、input/output delay这些参数把时间预算描述清楚。一旦你的设计里没有主时钟,工具就失去了它最依赖的"参考坐标系"。

异步SAR控制逻辑在这套模型里有几个天然的不适应点:

  • 内部没有全局时钟,工具无法用时钟周期去衡量和优化内部节点的时间关系;
  • 控制逻辑中存在大量组合反馈环路,工具对组合环的优化和分析能力非常有限;
  • 触发源来自模拟比较器边界,比较器输出的过渡过程和毛刺特性不完全是标准数字逻辑模型能表达的;
  • 事件之间的最短/最长等待时间,很难用常规约束句法直接描述。

更麻烦的是,综合工具在优化时往往会执行一些"看起来正确但对异步设计很致命"的变换:重组逻辑、吸收冗余、合并寄存器、移动锁存器。这些优化在同步电路里都能减少面积或改善时序,但放到事件驱动的异步SAR逻辑上,就可能改变事件之间的因果关系,造成RTL模型和网表行为的不一致。后面几章我按实际排查中遇到的频率,把具体问题拆开讲。

2. 翻车现场:握手与触发信号的隐藏毛病

2.1 把valid信号直接当CLK,综合后为什么会出现毛刺触发

我说过,异步SAR里最常见的写法就是把valid当作触发信号,直接接到寄存器的时钟端或者使能端。问题在于,真实电路里的valid不是无故产生的,它通常来自比较器控制逻辑对cmp_out的沿检测,或来自多个条件信号的组合。

assign valid = cmp_ok && dac_settled && !busy;

就这么一行组合逻辑,在RTL仿真里完美无缺:cmp_ok、dac_settled、busy这三个信号在时间上总是交错的,valid只会出现一个干净的脉冲。但综合后,这三个信号由不同的路径到达,逻辑门延迟各不相同。在最坏情况下,cmp_ok先翻高,dac_settled还没翻高,valid维持低电平;等dac_settled翻高时,busy信号刚好因为另一条路径的影响翻低,valid最终产生一个很窄的脉冲。

窄脉冲对寄存器时钟输入来说是极其危险的。寄存器不一定能正确识别这个脉冲,也可能识别了第一个上升沿,又因为脉冲太窄在下降沿附近产生亚稳态,甚至产生"以为看到了两个时钟沿"的异常行为。一旦SAR寄存器在这个错误时刻被触发,后面整串逐次逼近的码位就跟着错位。

我在实际项目中还见过一种更隐蔽的情况:valid在RTL仿真里看没有任何毛刺,但门级仿真打开SDF反标后,某条内部路径延迟变化,导致valid在一个转换周期内出现了两个额外的窄脉冲。虽然窄脉冲宽度只有几十皮秒,但仍能在某些PVT角下触发寄存器,导致SAR多翻转一次。这种问题最坑的地方在于:它和输入幅值、温度、工艺角都相关,可能统计上只是百分之一的概率,芯片实测才会偶发一下。

处理这类问题没有特效药,我的建议是两条路并行:一是从RTL层面主动切分,把valid生成逻辑尽量简单化,不要在一个组合表达式里堆太多条件;二是综合时对valid到寄存器时钟端的路径单独设置max_delay和min_delay约束,钳制它的到达时间和脉冲宽度。约束写法我会在第四章详细给出来。

2.2 异步复位释放路径上的竞争与"抢跑"

异步SAR控制逻辑里还经常出现异步复位/置位信号,而且这些信号往往不是外部主复位,而是由内部控制逻辑根据比较器状态临时产生的。比如某一位预置为1时需要置位SAR_code,下一次转换开始前又需要把某些寄存器复位清零。

当复位信号来自内部组合逻辑时,问题就来了:复位释放的边沿和valid触发的边沿可能存在竞争。举个例子,SAR_code更新后,控制逻辑要释放复位信号;与此同时,DAC建立完成事件又马上触发valid。在RTL仿真里,你用always块的优先级把"复位优先"写死了,看起来没有任何歧义。但在门级电路里,复位释放和valid触发是两个完全独立的物理路径,它们各自的延迟不同。如果复位释放那一拍比valid晚了几个门延迟,寄存器就可能先锁存了新码又立刻被复位清零,或者反过来:寄存器先被复位清零,然后才在valid边沿存入了一个不该存的旧值。

我印象最深的一次排查经历是:门级仿真里每次转换的第一个周期都正常,但从第二个周期开始,SAR_code的最高位始终为0。理论上MSB应该在第一次比较后就按输入电压幅值置0或置1,结果却总是被复位拖成0。把波形放大后才发现,置位信号只维持了一个非常窄的脉冲,在门级延迟下刚好撞上valid的触发沿,导致MSB的置位操作根本没成功。

这种"复位路径和事件路径竞争"的问题,在综合后的静态时序分析里往往看不到,因为write_sdf之前,工具默认这些内部生成的异步复位信号不是真实时钟域的一部分,很多设计者根本不会在STA报告里主动查它。我现在的做法是:只要设计里存在内部逻辑生成的异步置位/复位信号,就必须把它当作一个独立的"时钟类信号"来约束,并在门级仿真阶段专门观察复位释放时刻的信号交叠。

2.3 一种很典型的门级仿真错位波形

排错的时候,有一个波形很典型,我这里描述出来供大家对照。假设期望的一个5位SAR转换序列是:

10000 -> 11000 -> 11100 -> 11110 -> 11111

但门级仿真实际跑出来是:

10000 -> 01000 -> 11000 -> 11100 -> 11011

从第二位开始整条序列全都错位了。你可能第一反应是SAR算法写错了,或者是比较器结果反转了。但如果你把valid信号、比较器完成事件和SAR_code更新边沿重叠起来看,往往会发现:某一拍里valid出现了两个上升沿,SAR寄存器在同一周期内被触发了两次,于是码位凭空往前多挪了一位。

另一种更常见也更隐晦的错位是:输出码整体"少了一拍",比如某次转换只产生了N-1个有效码位,最后一个码位还维持了上一个大周期的旧值。这种波形通常意味着valid信号在某个转换周期内没产生,或者产生了但没有被寄存器正确捕获。原因是路径竞争让寄存器端看到的valid脉冲宽度过窄,寄存器在建立时间/保持时间窗口内没有稳定采样到有效电平。

如果你在门级仿真里也看到类似的"多了半拍"或"少了一拍"现象,我建议先别急着怀疑逻辑功能,按第五章的排错链路,先把RTL仿真和门级仿真的波形在关键信号上做一次逐拍的对比定位,往往比对着RTL代码一行行猜效率高得多。

3. 工具改坏了电路:综合优化与异步逻辑的冲突

3.1 组合反馈环被优化改变后的时序异常

异步SAR控制逻辑里几乎必然存在组合反馈环。举一个很典型的环:

比较器valid -> SAR更新 -> DAC切换 -> 比较器启动 -> 再次比较 -> 产生valid

这个环在RTL层面通常靠wire和assign互相连接,没有经过物理寄存器切分。综合工具看到组合环之后,不同工具、不同版本、不同优化等级下的反应不太一样:

  • 有的工具选择直接保留环结构,但会在优化时提取公共表达式、重组布尔函数,改变环上某个节点的延迟;
  • 有的工具把组合环当成"无时钟驱动逻辑",完全不纳入时序预算,结果时序报告里压根看不到这些路径;
  • 有的工具在开启datapath优化或retiming之后,尝试对环进行"切割"或"重定时",拆出来的结构可能引入额外的锁存或脉冲行为。

最典型的表现是:原本依靠valid之后若干门延迟才启动的DAC切换,因为环上某个节点的逻辑被重组得"太快了",导致DAC在比较器还没有完全建立好之前就开始切换。你从功能上看逻辑方程式完全没变,但因果关系的时序边界被工具悄悄挪动了。

我自己在综合一个12位异步SAR的时候遇到过类似情况:RTL里明明有一条延迟链用来产生"比较器启动"信号,确保DAC建立时间足够,综合后工具把延迟链里的一部分缓冲器优化掉了,理由是它们是"可消除的冗余缓冲"。对同步设计来说这些缓冲器确实冗余,但在异步逻辑里它们就是决定握手时序的"延时元件"。删除之后,DAC建立时间缩短了,系统功能在大部分输入下正常,可一到高幅值快速变化时,逐次逼近就会出现偶发错误。

所以我现在做异步SAR综合时,会在RTL代码里给这些关键延迟链加preserve属性,同时会检查综合后的网表结构,确认门数和延迟链级数没有被工具吃掉。

3.2 锁存器被悄悄合并、替换甚至消除的几种后果

异步SAR设计里,电平敏感锁存器几乎是标配,因为它天然适合描述"当某个事件条件满足时更新并保持"的语义。水平一般的RTL代码可能长这样:

always @(*) begin if (dac_ready) begin sar_code = next_code; end end

RTL仿真时,dac_ready为高时sar_code跟随next_code,dac_ready变低时sar_code保持原值。综合工具会把这个行为映射成一个锁存器。理论上没问题,但综合工具在优化时可能会对锁存器做几种危险操作:

  • 合并:如果两个锁存器的数据来源和使能条件等价,工具可能把它们合并成一个;合并后如果其中一个原本支持不同的数据到达时间,就会改变时序行为;
  • 替换:如果工具误以为设计里存在可用时钟,可能把电平敏感的锁存器实现替换成边沿敏感的寄存器,从而改变"什么时候更新"的语义;
  • 消除:如果工具分析出某个锁存器"看起来"输出可以被其他逻辑推断出来,它会直接把锁存器删除,换成纯组合逻辑。但异步事件中的保持语义一旦变成组合逻辑,电平保持的时间窗口就完全不受控了。

我在排查某同事那颗8位异步SAR时,就遇到过锁存器被工具自动合并的情况。原本RTL里有两个分别由"比较阶段"和"DAC建立阶段"控制的锁存器,各自完成不同的保持功能。综合后工具把这两个锁存器认成"等价可合并",合并成一个公共锁存器。结果就是:比较阶段还没结束,SAR码就开始提前更新,后续比较结果全部提前了半个周期,转换精度明显劣化。

遇到这类问题,第一反应不要是"综合工具为什么这么笨",而是"我该怎么向工具表达清楚我的设计意图"。最直接的做法是在RTL里给这些关键寄存器或锁存器加上dont_touch/preserve属性,禁止工具合并和替换。虽然会牺牲一点面积和时序收益,但异步SAR的控制逻辑本身面积不大,保住正确性比省那几百个标准单元重要得多。

3.3 形式验证在异步SAR上误报的全过程

很多团队做完综合都会跑形式验证,RTL vs网表的逻辑等价性检查。同步设计里这是很快的事情,几乎全自动跑完,报告等价。异步SAR一上形式验证,经常会出现两种结果:要么工具跑半天跑不完,要么干脆报"不等价"。

为什么形式上明明一致的逻辑会报不等价?主要原因有三个。

第一,组合反馈环会让形式验证工具的状态探索空间急剧膨胀。工具默认采用时序逻辑的建模方式:状态由寄存器决定,组合环只是两个寄存器之间的路径。但异步SAR里,组合环本身就是状态保持机制的一部分,这会逼着工具去分析环的稳定点,状态空间可能指数级爆炸。

第二,锁存器的建模方式与真实行为有偏差。大多数形式验证工具把锁存器建模成"使能高时透明,使能低时保持",这本身没问题。但如果工具在解析你的网表时把某些锁存器误判为组合节点,或者因为综合优化导致了结构差异,它就无法建立RTL和网表之间正确的映射关系,于是报出"不等价"。

第三,工具对异步置位/复位信号的处理比较粗。内部逻辑产生的异步置位/复位信号,如果驱动路径上带有组合逻辑,形式验证工具往往会走保守路径,直接把相关模块标记为"无法验证"或"失配"。

所以如果你在异步SAR项目上遇到形式验证报不等价,并不一定代表综合结果真的有功能错误。我的处理流程是:先确认报告出来的失配节点是否处于组合环或锁存器相关路径上;如果是,先跳过这些模块,验证纯同步边界部分是否等价;再返回处理特殊节点。一定要结合门级仿真的实际行为做最终判断,形式验证报告只能当线索,不能当唯一结论。

4. 没有全局时钟,约束该怎么写

4.1 不加异步约束时,综合工具默认做了什么

很多做异步SAR的朋友,包括早年的我,综合脚本里最常犯的错误就是只写了外部输入时钟的约束,内部异步节点全都不管。有人甚至认为"反正没有时钟,工具就不会乱动这些路径"。实际恰恰相反。

综合工具遇到没有时钟约束的内部节点时,它的默认处理可能包括:

  • 把内部信号当理想网络处理,认为路径延迟为零,因此在面积和延迟优化时根本不会优先考虑这条路径;
  • 把异步路径当成无关路径,不纳入时序优化,也不生成真实的时序报告,你查报告时根本看不到这条路径的延迟;
  • 在优化策略上倾向于最激进的面积优化,因为工具认为"反正没有时序要求";而这些激进优化很可能破坏异步事件的到达时间。

不夸张地说,不给异步路径写约束,等于把设计最关键的时间关系交到工具手里,让它完全凭默认策略瞎猜。所以,即便你的设计里没有全局时钟,也必须给内部异步节点建立一个"虚拟的时序参考系",然后对关键事件路径做显式约束。

4.2 三条最该单独约束的关键路径

以我现在的习惯,每次综合异步SAR逻辑电路,最少要针对三条路径写显式约束。

一是比较器valid信号到SAR寄存器的路径。这条路径决定了事件触发到达的时间。要同时约束最大值和最小值:max_delay限制传播不能太晚,否则整个转换周期变长;min_delay限制路径不能太快,否则可能在DAC尚未建立时提前触发。

二是SAR寄存器输出到DAC切换逻辑的路径。SAR码更新后,DAC阵列才会切换。这条路径的延迟决定SAR输出稳定到DAC动作之间的间隔,约束太松会导致DAC切换延迟,约束太紧则可能违反物理实现,所以一般设一个合理的max_delay。

三是DAC建立完成(或比较器启动使能)到下一次比较完成的路径。这条路径决定两次比较之间的最小间隔,直接和比较器速度、DAC建立时间有关。通常也要设max_delay,让工具明白这条路径是有时间预算的。

下面是三段TCL约束示例,可以作为参考基础,具体数值要结合工艺和你的频率预算调整:

# 比较器valid事件到SAR寄存器 set_max_delay 2.0 -from [get_pins u_comp/valid] -to [get_pins u_sar/sar_code_reg*/CLK] set_min_delay 0.5 -from [get_pins u_comp/valid] -to [get_pins u_sar/sar_code_reg*/CLK] # SAR寄存器输出到DAC切换控制 set_max_delay 1.5 -from [get_pins u_sar/sar_code_reg*/Q] -to [get_pins u_dac_switch/EN] # DAC建立完成到比较器再启动 set_max_delay 3.0 -from [get_pins u_dac_ready/ready] -to [get_pins u_comp/start]

再补充一点:如果工具支持异步时钟组声明,也可以用set_clock_groups或set_false_path把异步事件路径和真正的参考时钟隔离开,避免工具把它们拖进无意义的跨时钟域分析,导致大量violation报告淹没了真正关键的问题。

4.3 综合选项:关掉retiming,保留逻辑原貌

综合工具为同步电路准备的很多高级优化,在异步SAR场景下都是帮倒忙,尤其是retiming和register_merging这两类。

Retiming做的事情是把组合逻辑和寄存器边界重新划分,本质是移动寄存器,让每一级的时间更均衡。但对于事件驱动的异步逻辑,寄存器的位置本身就是"事件边界",移动寄存器等于移动事件触发的物理位置。一旦移动,valid信号和SAR_code更新之间的因果关系可能在网表里被重新解释,最终功能虽然逻辑等价,但时序行为完全不同。

Register_merging也类似,工具会把功能等价的多个寄存器合并成一个寄存器,这在同步设计里能减少面积。异步SAR里不同寄存器在不同事件窗口更新,合并后某个寄存器的更新时刻等于另一个寄存器的更新时刻,可能引入功能错误。

多条建议一次性给出:

  • 关闭retiming选项;
  • 关闭或谨慎使用register_merging;
  • 对关键模块单独设置dont_touch属性;
  • 在综合后的网表里抽查关键模块,确认锁存器数量和RTL预期一致;
  • 跑门级仿真时,对比综合前后锁存器/寄存器的数量变化。

如果你用的是带增量编译流程的复杂综合环境,记得在每次优化迭代后检查异步关键路径的时序报告,即便工具没报violation,也要人工确认这些路径确实被纳入了优化范围。

5. 排错完整链路:用证据定位问题

5.1 第一步:判断是功能错误还是时序错误

到这一步,假设你已经拿到了一个综合后出错的网表,仿真结果不对。我建议先做一次快速分类,不要直接扎进代码里读逻辑。

一个比较实用的测试是:分别跑带SDF反标和不带SDF反标(零延迟模式)的门级仿真。如果零延迟模式就错,说明错误是逻辑层面的,根因大概率出在RTL语义和网表结构不一致,比如锁存器被合并、组合环被优化改坏。如果只有带SDF反标才错,说明错误是时序层面的,比如建立时间不够、保持时间冲突、毛刺触发或复位竞争。

另一种分类维度是观察错误出现的规律。如果错误在所有输入条件下都固定出现,几乎不受频率和输入幅值影响,多见于逻辑结构被工具改变;如果错误只在高幅值变化、特定输入边界或高频下出现,且次数是偶发的,十有八九是时序竞争。还可以用抗干扰经验判断:相同网表在多一个工艺角仿真下错误概率明显不同,基本可以锁定是时序路径延迟问题。

下面这个表格是我常用的问题分类对照,适合贴在你调试记录旁边:

现象特征大概率性质优先排查方向
零延迟仿真也错逻辑功能不一致锁存器合并、寄存器替换、组合环优化
只有SDF反标后错时序问题valid路径毛刺、建立/保持冲突、复位竞争
错误与输入幅值有关比较器边界时序比较器valid到SAR更新的相对时序
错误与随温度/工艺角有关路径延迟敏感约束缺失、延迟链被优化
错误集中在转换末尾死锁或缺少收尾事件状态机收尾逻辑、握手信号未闭合

5.2 第二步:RTL与门级网表仿真的波形比对

分类之后,就要用波形比对来定位具体错误点。方法核心是"找到第一个不一致波形"。

具体操作步骤是:先准备完全相同的testbench激励,分别跑RTL仿真和门级仿真,让两种仿真输出相同格式的波形。然后按转换周期逐周期对比以下信号的跳变关系:

  • valid脉冲的个数和位置;
  • 每个上升沿时刻对应的SAR_code变化;
  • DAC切换使能信号的生效时刻;
  • 比较器输出cmp_out的采样点;
  • 所有异步复位/置位信号的生效与释放时刻。

一旦定位到某拍开始不一致,缩小时间窗口,把该时刻前后各几个时钟周期的波形展开,仔细对比valid和SAR_code的边沿关系。例如,RTL里valid只产生一个上升沿,而门级网表里valid在同一周期出现了两个上升沿,这时基本可以判定是毛刺或组合竞争触发了SAR寄存器。

我的实际经验是:自动比对脚本比手工盯波形靠谱得多。你可以在testbench里写一个断言检查器,在每个转换周期结束时比对当前SAR_code的期望值,一旦不符立刻打印仿真时间和内部信号状态。以下是一段简单的SystemVerilog断言示例:

property check_sar_code; @(posedge valid) disable iff (!rst_n) (sar_code == expected_code); endproperty assert property (check_sar_code) else $fatal(1, "SAR code mismatch at time %0t", $time);

当然,断言里怎么得到expected_code要结合你的模型,有时可以单独跑一个行为级参考模型,把期望码输出到一个文件,再在testbench里读入比对。那些偶发的、概率性的错误,靠人工看波形很难抓,自动比对跑几千个随机向量才有机会复现。

5.3 第三步:从形式验证失败中缩小真因

如果门级仿真发现了问题,同时形式验证也报了不等价,可以把两者结合起来缩小范围。形式验证报告的失配节点,通常能直接告诉你是哪一条逻辑路径的等价性出了问题。

我的做法是:

  • 先看失配节点是否集中在某个模块或某些信号上;
  • 如果是锁存器相关的失配,回到RTL确认该锁存器的使能条件,再在网表里查找合并后锁存器的驱动逻辑;
  • 如果是组合环相关失配,可以尝试在综合工具中把这些节点设成cutpoint,重新做形式验证;
  • 如果失配路径跨越了比较器接口,多半是异步边界建模的问题,可以在验证环境里把模拟接口信号排除掉,缩小到数字逻辑内部。

形式验证工具的输出文件里,通常会给出"失配点的输入锥(cone)"信息。顺着输入锥往前翻,你能看到RTL和网表之间结构差异最集中的位置。这种结构化路径往往比在仿真波形里大海捞针更直接。

5.4 一份可以直接套用的排查命令清单

下面是我做异步SAR逻辑电路综合后错误排查时常用的命令和检查点,你可以存下来当工作清单用。

# 综合阶段 # 检查组合环是否存在 report_loops -nworst 20 # 检查异步路径是否被纳入分析 report_timing -from [get_pins u_comp/valid] -to [get_pins u_sar/sar_code_reg*/CLK] -max_paths 20 # 检查被优化掉的锁存器 report_lockup -verbose report_qor -summary # 检查网表中寄存器/锁存器数量 report_design -verbose | grep -i "latch" # 门级仿真阶段 # 标准门级仿真命令示例 vcs -full64 -sdf typ:top:top.sdf +acc+3 -f filelist.f -o simv ./simv +ntb_random_seed=12345 # 仿真时开启SDF时序检查 $sdf_annotate("top.sdf", top, , "typ");

每次排查我都会做三件事:第一,确认组合环报告里没有"被工具拆得面目全非"的节点;第二,确认关键异步路径在时序报告里是可见的,而且和约束一致;第三,把所有核心里面用了valid当时钟或异步置位的寄存器找出来,写进一个checklist,仿真阶段专门盯它们的行为。

6. 多次排错之后,我最想提醒你的事

回到帮某同事查那个8位异步SAR的问题。最终定位出来的元凶,是综合工具把两个功能"看起来相同"的锁存器合并了,而合并后引入的提前更新,让SAR的码位错乱。RTL仿真和门级零延迟仿真之所以都没暴露,是因为错误只有在DAC建立时间和比较器valid路径一起成熟的情况下才会显现;一旦SDF反标加上,两条路径的物理延迟差才让问题变得可观察。

这几次排错之后,我有几条实际心得想分享。

第一,验证异步SAR逻辑电路时,不要只跑单一工艺流程(比如只跑典型工艺角)的仿真。至少快速跑一下慢工艺角和快工艺角两种极端条件,很多时序竞争问题在典型工艺下根本暴露不了,换个角就会立刻出现。

第二,在RTL阶段就要给可能被工具优化的关键节点加preserve属性。这不是矫情,也不是为了对抗工具,而是明确告诉综合工具:"这条路径的延迟和语义绑定了电路行为,请你不要擅自动它。"异步设计里"看着多余但实际负责时序"的延迟链、锁存器、组合环,都需要这种保护。

第三,调试前先建自动比对脚本。在项目开发初期就花半天时间搭好RTL与门级仿真的结果比对环境,会大幅缩短后续所有排错时间。异步SAR的错误多为偶发,靠拉波形肉眼找极其痛苦,让脚本去跑几千个随机向量,比自己试几十次高效得多。

最后再说一点:如果你手上也有一个"RTL仿真全对,网表仿真偶发错"的异步SAR设计,建议按这个顺序排查:先跑零延迟门级仿真确认是否纯逻辑问题,再检查valid路径的毛刺和脉冲宽度,再看锁存器和组合环有没有被工具改写过,最后检查有没有漏约束的异步路径。大概率你会发现,问题不在你的想法,而在工具对异步世界的不理解。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询