仿真卡死一般分两种,一种是仿真时间还在走,只是仿真一直结束不了;另一种是仿真时间不走了。
本文主要针对第二种情况,仿真时间不走了,肯定是在某个地方死循环了,有可能在验证代码中,也可能在设计代码中。当环境复杂时,很难定位问题在哪里,而且没有办法加打印信息。
典型问题
dv
出现在dv代码中,最为典型的是如下情况。当然这里只是简化了代码,往往在环境复杂时,很难发现。
1 2 3 4 | forever begin f = !f; // 没有@clk end |
design
除了在验证环境中容易出现死循环,在design中,也有可能出现死循环。这种情况更难定位,因为design可能是多个组合逻辑语句相互死锁,才会出现loop。
1 2 3 4 5 6 7 8 9 10 11 | wire a; wire b; reg f; assign a = (f==1)?(!b):0; assign b = (f==1)?(a):0; initial begin f = 0; # 100; f = 1; end |
当f=1之后,a变为1,b变为1,a又变为0,b又变为0……
这样就卡死在这个时刻了。
解决办法
增加编译选项
+vcs+loopreport+10000
在vcs编译时增加上述选项。
该方法在遇到上述dv问题时,并没有什么用。
该方法在遇到上述design问题时,会报出如下错误

之后去查看log就好了,log会报出问题所在信号。
1 2 3 4 | Constr : ContAssign Module : top_tb Instance: top_tb /project/tb/top_tb.sv : 5. (signal: a) |
一般只要找到了是信号a引起的,就容易分析出问题所在了。
tcl脚本
第二种方法是使用tcl脚本来打印出哪些代码在跑。
使用步骤如下:
[1] 创建loop_detect.tcl,放在仿真目录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/usr/bin/tclsh
proc loop_detect {args} { set help "-help" if { [string equal $args $help] != 1 } { config followactivescope on set i 0; while {$i < $args} { run_step incr i }
} else { puts "Usage: loop_detect <no. of iteration>" } }
proc run_step {} { redirect -f loop.txt -a {set x [step]}; redirect -f loop.txt -a {set y [scope]}; puts $x; puts $y; } |
[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大概是下图的样子。很快我们也能发现问题。
