根据海思验证大牛一文《总结我的思路,如何在验证中发现和定位Bug》整理而得。
很多新晋的验证人员抱怨,这么多信号,这么复杂的连接关系,千头万绪,眼睛都看得长挑针,还是看不出东西。OK,我说,这是没办法的事情,看波形,追波形,是一个经验积累的过程,任谁都逃不掉。越是看,越是明白,越是不看,越是不懂。看得多了,自然就知道应该抓那些信号,如何分类,如何追溯了。所以我奉劝某些希望通过全自动的Log和信息推导结果,或者每次一有问题就找设计人员看波形的验证人员,回头是岸。波形,是逻辑运行的最真实的表现,逃不掉的。
看波形首先有两个基本的看点。
先看X和Z。
任何一个波形,无论是验证的前期、中期、后期,到手之后,先刷屏,找X和Z,确认。某些Z和X是可以存在的,例如某些IP模型,或者未初始化的寄存器和RAM,但芯片开始正常后,Z和X,都不应当存在。
OK,我承认这个经验非常简单,某些高层领导可能认为这简直就是幼稚。可惜,可惜的是,我至今为止看的,所有项目的波形,都能够在这上面找到Bug,甚至我可以预计下一个项目,我继续看波形,还是能够找到。
以我自己设计的L2 Cache为例,一个多年验证经验的老员工负责验证的,至今已经在多个项目中量产,还是在最近检查波形的时候发现有一个文件wire声明时把信号名写错了,悬空了(因为该信号是input,隐含了wire声明,所以不影响功能)。
OK,X和Z,一定会存在,第一时间找到它,可以节省非常多的验证定位时间,否则追波形半天发现是X,真是浪费青春。X和Z,所对应的Bug,可能有如下几种:
1、IP(包括Memory、PLL、Serdes等等)例化时,某些信号悬空未接。也许某些模型允许Power信号悬空,或者某些信号是悬空给DFT处理(当下给DFT处理的信号是接零),但大多数IP,输入信号是不可悬空的;
2、信号位宽不匹配、信号多驱动、声明的信号名称写错、TB级互联错误或TB中遗漏的Force(额外小心隐藏的Force),不要相信nLint,特别是在芯片顶层或
3、后仿真时序不满足时的X态传递;
4、功能错误,某些模拟IP未能正确操作;
5、功能错误,导致管脚冲突;
6、功能错误,未能合理使用无复位端的寄存器和未初始化的Memory。
再看时钟。
很多验证人员不看时钟。经过我反复的证明,这是一个非常普遍的现象(经常在项目验证后期协助定位时钟不对齐导致的环境问题)。只要TC能够打印Pass,很多验证人员不关心时钟是否有问题(甚至很多新验证人员,根本不明白∆ Delay的概念)。大多数情况下,时钟不会有问题?No,大多数情况下,系统验证,时钟都有问题。
记得以前在一个项目中推动CRG设计定义了一个规范,时钟分频寄存器,延迟0.2ns,其他寄存器,延迟0.3ns,分频的原时钟,在输出前延迟0.2ns对齐,不知道看到本文的,数字平台部的验证人员,有多少能明白其中的用意?不解释,不明白的请自行蹲墙角反省。
再想起一个以前海思的设计规范,要求寄存器赋值,不可加延迟,也是让人在风中凌乱啊。下面这个逻辑,寄存器赋值没有延迟,仿真能正常工作否?答案是可以!如果上帝比较仁慈,或者验证人员对仿真器的always执行顺序无限了解。
always@(posedge clkx2) clk <= ~clk;
always@(posedge clkx2) b<= a;
always@(posedge clk) if(clken) c <= b;
所以,在看完X和Z后,要将所有时钟拉到波形中Check,看是否所有同步时钟(包括1:N倍频)的时钟沿是否严格对齐,CLKEN时钟能够正确将倍频时钟上升沿罩住,关键地方寄存器赋值是否有Delay(如果时钟间不存在∆ Delay,寄存器赋值可以没有Delay)。
OK,上面两种情况说完,我们进入正题,怎样看波形。
如何在一个看似无限复杂的挂死波形中定位根因?
如何在后仿波形中发现可能的问题?
如何在表面上没有问题的波形中发现问题?
面对波形,首先要端正心态,不要认为看波形是浪费时间,也不要因为一时无法发现其中的问题而焦虑烦躁,更不要盲目乐观,认为已经没有任何问题。要执着、坚定,充满勇气。
先不要看波形,对,先不要看,这是我很重要的经验之一。要先思考,我的做法是对照架构图,虚拟一个芯片运转的场景,即在脑海中想像一下当前这个激励下,波形应当是怎样运作的,激励怎样进入系统,然后怎样完成协议解析和转换,怎样到达了总线,然后出现DDR的吞吐,然后CPU取指、取数,完成处理。
OK,也就是说,先要在心中预留一个完美的Scenario。心中有了虚构的波形后,再使用Verdi打开波形。抓关键信号,分组,标识不同颜色,这些奇技淫巧应该不用多说,很多兄弟都比我这个验证原旨主义者来得厉害。只是需要说明的是,抓多少信号,怎样分组,很需要斟酌。其实原则只有一个,让尽可能精炼的信号在一屏内显示,这和代码的精简是一个道理。信号除了按功能分类,还要按信息量分权重。所以还是要说,很多验证人员,用着花哨的手指技法,一屏一屏的信号抓,刷刷几屏下来,跟瀑布一样,很是壮观,往往Group的数量比我总共抓的波形数量还要多。操,看个AXI总线,把arlock信号和arvalid信号一起抓出来,除了催眠看波形的人之外,有其他意思吗?以AMBA总线为例,APB先看PADDR、PSEL、PENABLE,AHB先看HADDR、HTRANS、HREADY,AXI先看各个通道ADDR、VALID、READY,如果这些信号不能说明问题,再逐步增加辅助信号观察,尽量保证在一屏中显示所有有效信号,如果信号太多,宁可删除部分。
然后,将展开的波形和脑海中已有的场景进行对照,看数据流是否按照脑海中预期的构想而流动。一般来说,实际波形和预想都不太能够对上,最开始的大多数情况下,波形是正确的,而脑海中的预想存在不足,这主要是因为我自己对架构的细节理解还不充分,对某些特殊逻辑处理方式不熟悉,或者某些逻辑相互连接后新增的耦合关系不了解等等原因导致。而这个时候,在我看来,也正是一个最好的时机,来进一步熟悉和理解芯片真实运转流程,弥补自己对系统结构、互联设计中各个细节的理解不足。在对细节的进一步理解和澄清的过程中,我会逐步修正心中虚构的波形,使其逐渐接近真实的运作。当然,在修正过程中,会出现某些确实表现异常的波形,一些明显出乎设计预期的时序出现。OK,这是一个岔路口,先记录*.rc波形现场,然后对该出乎意料的时序进行进一步深入追溯。正如前面所述,我常常在已经Pass的波形(或后仿波形)中发现Bug,通常都是从这样的岔路口开始的。也许这个岔路口最终证明逻辑没有问题,还是细节理解不足导致,但也许就是一个芯片难以发现的致命缺陷。
看到这里,也许有同志会问,挂死的波形呢?怎么还没追挂死的点呢?Yes,就是还没开始,无论是挂死的波形,Fail的波形,还是Pass的波形,在其实际波形和我大脑中虚构的波形没有完全吻合之前,我是不会开始定位问题的。这简直是浪费时间?嗯,在最开始定位的阶段确实如此,但在验证进入中后期之后,正常的波形和我虚构的波形已经调频到一个波段了。和波形到手,从前到后一扫,寻找那些地方异常,然后,半小时发现问题,并不困难。当然,还是要说,我的经验,是不适合那些平时就只看Log,忽视波形的人的。
最后,我还是共享一些我定位复杂挂死波形的根因的经验。起点,定位挂死的起点在那里?或者说,从那里开始追?很多同志认为寻找一个合适的起点很重要,或者说最好直接就找到引发挂死的点。我说,No!!找到直接引发挂死的点,或者和该点直接相关的起点,是很困难的,我不做这种类似分析双色球中奖率的事情,任何挂死的波形,第一时间能够获得的信息,都是表象。我会将任意一个被阻塞的操作作为起点,开始我溯溪的旅途(请确信,无论那个溪流,最终都会汇到唯一的源头)。如有可能,用笔在沿途做下记号,保证在偏离方向的时候能够返回。溯溪的路途有艰辛、险阻,我看过太多的兄弟在中途放弃,或另寻他路,而有时候,他离最终的源头,仅一步之遥,所以,最后一个建议,请保持一颗坚定和勇敢的心。
最最后,再补充一点后仿定位的思路,供参考。
1、还是先关注时钟,每一个模块,clk和clken相位是否正确(PR有时会对时钟取反,需要注意);
2、关注有门控功能的时钟和复位,确认是否存在毛刺;
3、把Top层所有管脚和oen、I、C信号抓出来。除掉红色黄色,观察有特殊变化的oen、i、c信号,尤其是和管脚值不符的,还有毛刺;
4、观察所有异步接口的时序,基本上都会发现毛刺。例如EBI、Efuse,确认毛刺是否影响功能;
5、观察顶层或Subsys独立处理的信号,特别针对还不够成熟的集成人员的特殊设计,例如testmode、rst_out、系统控制器特殊的配置和检测信号;
6、关注跨团队的模块,例如功能可控的Memory BIST;
7、以上所有这些,MAX和MIN会有不同,要仿真Typical时序,并且确认以上的内容;
8、后仿的波形,需要结合Log中的Warning一起Check。