门级仿真笔记

最近接到一个后仿的工作,之前没有接触过,查阅资料后,找到如下一篇较深刻的文章,转载待用。原文《当我们做后仿时我们究竟在仿些什么》---作者ICSOC公众号

1.什么是门级仿真
后仿即门级仿真(gate level),是和RTL(register transfer level)相对应的。所谓网表(netlist),就是一堆基础单元(比如standard cell、比如sram cell)之间的连线(net)的列表,是和电路图形相对应的。门级网表通常可以指综合之后得到的网表(没有时钟树),也可以指布局布线之后的网表(带有时钟树)。

需要明确的是,门级网表中只是连接关系的列表,并不包含基础单元本身。基础单元的行为,是通过各自的仿真模型(model)来体现的,它通常是独立于门级网表存在的。

相对于RTL仿真,门级仿真占用的计算资源虽然很多,但是在静态时序检查(STA)工具普遍应用之前,带时序的动态门级仿真几乎可以说是唯一的timing sign-off手段了。

门级仿真可能分为两种,一种是带时序反标(back-annotation)的门级仿真(布局布线之后的仿真,也叫后仿);一种是不带时序反标的门级仿真(零延时仿真,综合的网表就可以做,因为在布局布线之前,所以也叫前仿)。

2.门级仿真目标:
检查时序约束(SDC)的完备性——防止约束的遗漏
检查异步电路的时序——STA工具无能为力
检查网表的完备性——防止综合、布局布线过程中的意外
为后续流程如功耗(Power)分析、压降(IR Drop)分析提供波形——更准确
测试向量的仿真——只有门级网表才包含扫描链

3.后仿的sdf信息
后仿用的时序信息通常包括延迟信息、时序检查时间,一般都用标准的SDF(standard delay format)格式的文件提供。在SDF中有两种类型的延迟信息。一种是连线的延迟信息;另一种是单元的延迟信息。连线的延迟信息不多说,单元的延迟通常是根据单元时序库(timing library)中定义的timing arc,从电路图形中间接提取计算出来的,而这些timing arc,要和仿真模型中(specify block)定义的io path要一一对应,在反标过程中才能标注成功。

那为什么叫反标呢?因为通常设计电路都是根据事先定义好的设计规格,而设计规格中就包含了时序的规格(例如SDC)。所以当电路设计好了,时序信息也确定了,把这些时序信息标注到电路的网表中,实际上是一个回溯的过程,所以叫反向标注。SDF实际上也可以提供类似SDC一样的前向标注的时序信息,指导电路的设计实现。另一方面,基础单元的仿真模型中默认也是有时序信息的,通常是单位时间或者零时间。所以用电路的真实时序信息标注的过程,其实是一个覆盖默认时序信息的过程,所以也叫反标。

覆盖这个概念特别重要。因为只有原来有,才谈得上覆盖。很多SDF标注的错误和警告,追根溯源都是和覆盖有关的。

SDF文件通常是STA工具(读入网表、时序库、RC参数)产生的,这里也要特别注意SDF的版本,目前常用的是2.1和3.0两个版本。后仿的时候注意SDF的版本和仿真模型的版本要保持一致。这两个版本比较明显的一个区别就是removal的检查,2.1版本不支持这个timing check,而是用hold替代实现。

某个corner的SDF中,通常会有一组或两组或三组时序值,max、typical、min(MTM)。在仿真器读入SDF的时候,要指定使用哪一组。避免出现指定的组的时序信息不存在的情况。

STA产生SDF的过程中,可以把异步接口部分的时序检查禁止掉(通过放松检查时间),比如2-DFF的同步逻辑中的第一级DFF的setup和hold检查。从这里也可以看出代码风格的重要性,代码风格好,STA工具可以很轻松的把这些寄存器逻辑用某种模式匹配出来。代码风格不好的话,只能通过有问题的后仿的多次迭代,把这些地方分批找出来,效率可想而知。

通过对网表的分析和抓取,还可以生成在仿真过程调用的初始化寄存器值的脚本,避免X态不必要的传递。

后仿开始前,一定要把详细的SDF反标报告打印出来仔细检查。需要把错误全部解决掉,警告视情况要解决大部分。带时序的后仿,一定要注意仿真器是否关闭了notimingcheck和nospecify的选项。如果有nospecify,那么SDF中的时序信息就反标不到仿真模型中(仿真模型的时序类型定义在specify block中);如果有notimingcheck,那么后仿过程中就不检查时序违例,后仿就失去了最大的意义。

后仿通常都很慢,如何加快后仿的速度呢?编译器通常都会提供编译时、运行时优化程度的选择(例如vcs的debug系列选项)。优化程度高,仿真速度就快,交互性就差。更可怕的是,优化程度高的时候,编译器会采用一些激进的优化策略,会对时序调度产生一些看似微小实则可能决定成败的影响。如果在综合网表上跑零延时的ATPG仿真,碰到了莫名其妙的错误(尤其是用S家的MAX Testbench),那么试试加上+debug_pp,降低一点点优化程度,仿真结果会有意想不到的改善。

带时序的后仿开始阶段,建议都dump一些波形出来,看看波形上的延时和SDF中的延时信息是否保持一致,这有助于对反标过程的理解和后仿整体进度的把握。

4.VCS工具仿真设置
初始化寄存器的值
有时候后仿中因为各种正确和不正确的原因,有些寄存器希望能有一个明确的初始值。那么可以准备一个类似下面内容的文件。
![在这里插入图片描述](https://img-blog.csdnimg.cn/6ee9608d5bbd4cf3b878a79896164a48.png

如果需要初始化的寄存器比较多,那么可以在PrimeTime或者其它工具里把网表中所有的触发器都遍历写出来,生成上面格式的文件,然后酌情做一些删减。

还需要准备一个编译时选项需要调用的列表,里面包含了上面初始化寄存器文件中所涉及的寄存器例化时所用到的reference单元,内容类似下面这样。这个文件的目的就是告诉仿真器,在编译的时候需要特殊处理这些标准单元,以便运行时可以做某些操作。

在仿真的零时刻用下面的方式加载这个文件

当然别忘了启动vcs的时候加上-debug等选项,打开ucli功能。

关闭某些寄存器的时序检查
后仿过程中可能有一些不必要或者不想检查的时序,尤其是两级同步的第一级DFF,通常不关心它们是否有时序违例。可以准备一个类似下面的文件。

在仿真的时候用下面的选项加载这个文件,这样在后仿过程中将不对这些寄存器做时序检查,避免不必要的时序问题引起X态传递。

生成VCD文件
芯片实现的一些流程需要后仿写出波形文件,比较常用的就是VCD格式的文件。VCD是个不压缩的文本格式,因为兼容性好的原因一直得到各种流行工具的支持。当然它的特点也决定了它的缺点,那就是文件太大,会拖累本来就慢的后仿速度。

可以变通的一个方案是,后仿先写出压缩比好的FSDB文件,再利用工具转成VCD。并且转换过程中可以指定起止时间,这样一次后仿,就可以为不同的应用生成不同的VCD文件。

仿真中写出FSDB的系统函数不必赘述。

FSDB转VCD的工具通常在Verdi的安装目录。

基本的用法大概是这样的,-bt是begin time,-et是end time

5.异步电路之间必须消除毛刺

之前提到过,数字电路后仿的一个主要目的就是动态验证异步电路时序。异步电路的时序是目前STA工具无法覆盖的。

例如异步复位的release是同步事件,其时序是可以靠STA保证的;但是reset是异步事件,它的时序只能靠设计来保证、动态仿真来检查。产生reset的逻辑可能来自多个时钟域,但是在送入异步复位电路的时候,还是需要在设计上做到最终是单独一个时钟域的触发器输出。这样才能保证异步复位信号本身无毛刺。

话说回来,现在的代码静态检查工具,已经能够很好的检查出类似的CDC问题了。不过工具虽然强大,但决定工具发挥作用大小的还是站在工具背后的人。

所以后仿成了最后一道关口。

遗憾的是,在上面这个例子中,后仿这个关口也并不是百分百能截住所有问题。如果后仿侥幸发现了类似的设计问题,真是应该去买张彩票、改行去捞鱼了。为什么捞鱼呢?因为整个设计流程肯定漏洞很多,说不定是一张上好的渔网。

6.X 态的问题

后仿中,难免会碰到X态的问题,而且波形工具还很贴心的用红色绘制出来,血淋淋的、吓你没商量。如果STA都干净了,很多时候X态还是异步电路造成的问题。

大家都知道,多bit信号跨时钟域的时候,除了用同步指示信号的方法外,常用的还是用异步FIFO。异步FIFO形成读数据的逻辑里,可以分为两部分。一部分是写数据,这部分是写时钟域的,是异步跨时钟域的。另一部分是读地址,这部分是读时钟域的,是同步的。大部分情况下,读数据中呈现的X态,是因为写数据的异步造成的。而异步FIFO的设计,是需要保证写数据稳定足够的时间(多个读时钟周期),以便读时钟来稳定采样的。

所以在这样的情形中,读数据局部出现了X态(时序违例),是不应该影响正常功能的。

可以看出,芯片设计是一个系统工程,不但设计、验证和流程是紧密结合在一起的,而且还有许多设计者很少考虑到的因素也参与其中,比如进度要求,比如芯片运营(chip operation)等等,都会在我们芯片设计的整个过程中产生影响。最近这个芯片项目,做得真是很辛苦,也感触很多,希望能有时间做深入的思考和总结,分享给各位读者。

7.负延迟问题

就像人类容易接受自然数,但对于负数缺乏某种直觉上的认识一样;后仿过程中经常出现的 Negative Delay 和 Negative Timing Check 也非常容易使人困惑。

Warning-[SDFCOM_NICD] Negative INTERCONNECT Delay encountered

今天这篇首先简要分析这些 Negative 们产生的原因,然后看一下 EDA 工具是如何处理它们的。

产生 Negative Delay 的原因

从根本上来说有两种原因。一种是测量的原因,比如输入和输出信号的观测方法不同,导致输出信号反而比输入信号在时间上提前;一种是信号在传输过程中真实发生了某种变化,导致信号跳变的提前。

具体原因大概分下面几种。

Voltage Converting

信号在不同电压域之间的转换可能会导致负延时产生,如下图所示。

假设都以 50% VDD 为信号跳变的阈值,那么如果信号从高电压域输出到低电压域,50% VDD 对应的时刻反而会提前,导致负延时的出现。这种极端情况出现的前提是信号的 Transition Time 足够的大,连器件的正延时都不足以抵消电压下降带来的负延时。

Threshold Converting

阈值转换的原因其实类似于电压转换,如果输出负载的阈值低于该器件的输入阈值,并且信号的 Transition Time 也足够的大,那么从观测者的角度,信号在输出时被观测到逻辑跳变的时刻反而提前于输入跳变的时刻。

Noise

信号在传输过程中难免受到一些干扰,如果这种干扰来自于相邻的器件或者走线,就称之为串扰(crosstalk)。串扰可能造成信号传输的滞后或者提前。

造成提前的情形如下图所示。

红色实线表示输入信号;绿色虚线是没有串扰的输出信号,如果在这个输出信号跳变之前有个串扰发生(黑色实线),会在输出上产生一个很短的高脉冲(绿色实线),和原本的输出信号合起来看,就相当于输出信号的跳变提前了。如果这个提前量足够大,就相当于该器件有了一个负延时。

Calculation

还有一些负延时来自于 EDA 工具特定算法的计算过程。比如时序模型做数值计算过程中引入的误差;针对 stage delta delay 和 net delay 分别做 derating 可能引入的负值。这些理解起来不那么浅显,就不做详细的解释了。

EDA 工具如何处理 Negative Delay

这个问题有点复杂,因为各家 EDA 公司的仿真器都有不同的算法来解决。

从直观的角度来考虑,一个负延时总归是要结合其相邻的器件延时、线延时来解决的,用整体更大的正延时来抵消局部的负延时。

有些仿真器干脆做简化处理,把从 SDF 中读取的负延时直接变为零延时。这种做法无可厚非,是符合 Verilog 和 SDF 标准的。

打开 VCS 仿真器的负延时特性,就是在编译时加上-negdelay选项。

另外,PT 写出 SDF 时是默认带有 Negative Delay 和 Negative Timing Check 的,如果不想写出这些负值,需要加上如下的特定选项,这时 PT 会自动把相关负值都变成零。

pt_shell> write_sdf -no_negative_delays {timing_checks | cell_delays | net_delays} postsim.sdf

产生 Negative Timing Check 的原因

Negative Timing Check 中的 Negative 其实和 Negative Delay 中的 Negative 不太一样,前者只是描述器件时序特性参数时规定的一种算术表达形式。

Positive Setup/Hold Timing Check

先看一个常见的 Setup Limit 和 Hold Limit 都为正值的例子。

下图是一个标准单元 D 触发器的框图,我们接下来所讨论的时序检查都是相对于最外层框图所对应的管脚。

仿真模型中用来检查时序的语句如下,其中的 Setup Limit 和 Hold Limit 的具体数值都是从 SDF 文件取出后反向标注到网表的。

$setuphold (posedge clock, data, 2, 3, notifyreg);

这种语法模式下,Clock Event 的时刻规定为 0 时刻;Data Event for Setup Check要早于 Clock Event;Data Event for Hold Check 要晚于 Clock Event;符合这种一般情况的时序参数,包括 Setup Limit 和 Hold Limit 都用正值来表示。

但是标准单元内部因为一些特殊的设计,会造成 Clock 和 Data 到达内部真正的时序器件的延时不同,这样从外部来看,时序参数会有一些不同的情况。

Negative Setup Limit

从下面的示意图可以看出,Negative Setup Limit 的产生主要是因为标准单元内部 Clock 上的延时相对较大,从外部来看,Data Event for Setup Check 就可以晚一些来,如果晚于 Clock Event(时刻为 0),就用负值来表示(和早于的情况相反)。

$setuphold (posedge clock, data, -2, 7, notifyreg);

Negative Hold Limit

从下面的示意图可以看出,Negative Hold Limit 的产生主要是因为标准单元内部 Data 上的延时相对较大,从外部来看,Data Event for Hold Check 就必须早一些来,如果早于 Clock Event(时刻为 0),就用负值来表示(和晚于的情况相反)。

$setuphold (posedge clock, data, 7, -2, notifyreg);

EDA 工具对于 Negative Timing Check 的支持

当时序参数存在负值的情况时,必须要用 $setuphold 以及 $recrem 来表示;而不能用单独的 $setup$hold$recovery$removal。具体语法如下。

$setuphold(reference_event, data_event, setup_limit,
hold_limit, notifier, [timestamp_cond, timecheck_cond,
delayed_reference_signal, delayed_data_signal]);

$recrem(reference_event, data_event, recovery_limit,
removal_limit, notifier, [timestamp_cond, timecheck_cond,
delayed_reference_signal, delayed_data_signal]);

并且从 STA 工具写出 SDF 文件的时候,需要设置恰当的选项,来支持这种标注语法。例如:

pt_shell> write_sdf -version 3.0 -include {SETUPHOLD RECREM} postsim.sdf

同样,在调用仿真器的时候,例如 VCS,需要加上 +neg_tchk 的编译选项来支持 Negative Timing Check 的动态仿真。

---------------------------碰到的问题记录---------------------------------------------

8.前仿碰到的问题

a.在rtl设计中cluster中4个core采用generate实例化,hart_id寄存器为常量,在综合时,hart_id被优化掉,导致前仿在做核同步算法时,读取到所有core的hart_id均为0,不符合设计预期;

b.如下代码,在处理主处理器与协处理器配合问题时,状态机寄存器未设置复位信号,导致综合后状态异常。图1添加flush_cycle_ex4后,逻辑符合预期。

总:以上两个问题在rtl仿真阶段均未发现问题,综合后被很容易识别出来,也提示RTL设计人员代码设计规范的重要性及可综合性。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值