How To: Debug a Hung Simulation
There are several possibilities:
- Your code is stuck in an endless loop. Events are not being processed.
- Your code is stuck in a #0 delay loop. Events are being processed, but time is not advancing.
- Events are being processed, and time is advancing, but progress subjectively seems slow.
How you proceed depends on what you think the cause is. You can try all of the tips below.
1. Debugging Endless Loop
If you are running interactively, press
C once. DSim will check for
C at the end of each timestep and abort the simulation if detected. If the simulation does not abort, then you likely have an endless loop.
At this time, DSim does not have any debug capability that can help with this case. You may have to kill the UNIX process to terminate the simulation.
2. Debugging #0 Delay Loop
If you have a #0 delay loop (case 2 above), then the simulation will terminate with a message like:
=F:[IterLimit] iteration limit (currently 1000000) exceeded; aborting at 0.
Your next step is to recompile the code with the addition of the
-g command line option. This option causes additional debug information to be generated, at which point you might get the line number causing the problem:
Threads scheduled for current timestep: Inactive initial block top @ test.sv:8 =F:[IterLimit] iteration limit (currently 1000000) exceeded; aborting at 0.
Here we see the offending code is likely at test.sv, line 8.
Zero-delay loops often occur in clock generators:
always begin #period/2; clk = ~clk; end
period is ever zero or contains X/Z values, you will effectively have a zero delay. This may happen, e.g. in a PLL model, where the delay is computed as a function of the PLL configuration and other internal state. You can add an assertion for this as follows:
always begin if (!period || ^period === 1'bx) begin #1 $display("%m: %s:%0d: Bad input to clock generator", `__FILE__, `__LINE__); $finish; end #(period/2); clk = ~clk; end
#1 delay before issuing a message works around difficulties many waveform viewers have either displaying or scrolling to events that occur on the very last simulation timestep. The
$finish ensures that no zero-delay loop persists. The log message must be specific enough to isolate the problem to a single instance of the clock generator.
3. Debugging Slow Progress
Ideally, a testbench should emit enough messages during a run to demonstrate progress. However, you may have a test that uses third-party IP, issues no messages, and is therefore unclear as to whether progress is being made. Alternatively, you may have a test that makes progress, but you suspect that different test phases are causing slowdowns that warrant further investigation.
DSim has a heartbeat feature that may help:
dsim -heartbeat 1us ...
-heartbeat option takes a time value. If no unit (ms, us, ns, etc.) is provided, then the default unit is the simulation time precision. After intervals of the specified time value, a progress message will be output to the system log:
=N:[Heartbeat] sim time = 1000000000, elapsed wall time = 8.27s, rate = 120925287 ticks/s, overall rate = 120925287 ticks/s =N:[Heartbeat] sim time = 2000000000, elapsed wall time = 15.63s, rate = 135819775 ticks/s, overall rate = 127940496 ticks/s =N:[Heartbeat] sim time = 3000000000, elapsed wall time = 16.99s, rate = 738286405 ticks/s, overall rate = 176608187 ticks/s
elapsed wall time is the time, in seconds, since the simulation was started.
rate is the number of timesteps (unique simulation time values, irrespective of simulation region) executed per second since the last heartbeat message.
overall rate gives the rate since invocation from time zero.
In the example output above, execution during the last heartbeat interval ran about 6x faster than the previous intervals.