仿真卡死一般分两种,一种是仿真时间还在走,只是仿真一直结束不了;另一种是仿真时间不走了。
本文主要针对第二种情况,仿真时间不走了,肯定是在某个地方死循环了,有可能在验证代码中,也可能在设计代码中。当环境复杂时,很难定位问题在哪里,而且没有办法加打印信息。
典型问题dv
出现在dv代码中,最为典型的是如下情况。当然这里只是简化了代码,往往在环境复杂时,很难发现。
1 | forever begin |
design
除了在验证环境中容易出现死循环,在design中,也有可能出现死循环。这种情况更难定位,因为design可能是多个组合逻辑语句相互死锁,才会出现loop。
1 | wire a; |
当f=1之后,a变为1,b变为1,a又变为0,b又变为0……
这样就卡死在这个时刻了。
解决办法
增加编译选项
+vcs+loopreport+10000
在vcs编译时增加上述选项。
该方法在遇到上述dv问题时,并没有什么用。
该方法在遇到上述design问题时,会报出如下错误
之后去查看log就好了,log会报出问题所在信号。
1 | Constr : ContAssign |
一般只要找到了是信号a引起的,就容易分析出问题所在了。
tcl脚本
第二种方法是使用tcl脚本来打印出哪些代码在跑。
使用步骤如下:
[1] 创建loop_detect.tcl,放在仿真目录。
1 | #!/usr/bin/tclsh |
[2] 增加编译选项-debug_all.
vcs files -debug_all
[3] 增加仿真选项支持ucli
simv -ucli
[4] 执行tcl脚本
ucli> source/do loop_detect.tcl
[5] run
ucli> run <time> # point where simulation hangs
[6] 执行函数
ucli> loop_detect 1000 # no of iterations
之后会生成log.txt文件。
上述dv情况,log大概是下图的样子。很快我们也就能定位到死在哪里了。
上述design情况,log大概是下图的样子。很快我们也能发现问题。
总结
从上面看来,增加编译选项的方法需要重新编译,耗时较长,只有vcs能用,并且还不能发现dv的问题,但是报的信息质量较高,基本能定位到时哪个信号出现loop。tcl脚本方法,不需要重新编译,理论上irun也能用(但我没试过),可以查找dv和de的问题,但是报的信息太多了,所有执行的代码都会打印,需要逐条分析,当loop环太大了,查找也可能需要点时间。