Debugging
Static checks
The sim-versus-silicon divergences a passing testbench will never catch.
A design can pass every test it has and still be wrong on real hardware. Simulation and silicon disagree in a small number of well-known ways, and those ways can be looked for directly, without a testbench and without running anything.
Three layers of checking
| Check | What it looks at |
|---|---|
| Lint | Your sources, statically: width mismatches, unused and undriven signals, unintended latches, unreachable code, and the rest of the standard catalogue. |
| Synthesis check | What a synthesiser actually infers from your design, which is where a latch you did not intend or an undriven net tends to surface. |
| Sim/synthesis divergence scan | A focused set of rules for the places simulation and hardware are known to part company. This is the layer a passing testbench cannot substitute for. |
A debug run reaches for these itself, particularly when the testbench passes and you are telling it the design is wrong anyway. Where a check cannot be run, it reports itself as unavailable rather than quietly reporting nothing found; an empty result and a missing result are not the same claim.
What the divergence scan looks for
Broadly, the constructs that behave one way in a simulator and another way on a device:
- State that starts undefined. Registers with no reset, or an initial block standing in for one. Both give you a defined value in simulation and whatever the fabric feels like on the device.
- Unsafe clocking. A clock domain crossed without a synchroniser, a clock generated from combinational logic, or one register driven from two clocks. None of these can fail in a zero-delay simulation, and all of them can fail on a board.
- Constructs the simulator honours and silicon ignores. Delays in synthesisable code, and comparisons against undefined or high-impedance values.
- Assignment style that changes evaluation order between simulation and synthesis, most often a blocking assignment inside a clocked block.
These are heuristics, and they say so
The scan reads your sources rather than fully elaborating the design, so every finding carries a confidence level and is meant to be confirmed before it is reported as a root cause. A high-confidence finding is usually worth acting on directly; a low-confidence one is a place to look.
Note
Testbenches are excluded from the scan by default. Delays and four-state comparisons are correct in a testbench and wrong in RTL, so including them would bury the findings that matter under findings that do not.
Reading the findings
warning divergence rtl/uart_rx.v:38 high
`baud_cnt` is never reset. It starts undefined in simulation and at an
arbitrary value on the device.
warning divergence rtl/uart_rx.v:71 medium
`rx_sync` crosses from the rx clock domain with no synchroniser.
warning lint rtl/fifo.v:22
Bit-width mismatch: assignment of 9 bits to an 8-bit target.Findings are grouped by severity. An error from lint or synthesis is usually something that will not build. A warning is usually something that will build and may not do what you meant.
Where the checks stop
There is no timing analysis and no power analysis here, and neither can be inferred from these results. If a design passes everything on this page and still fails on the board, the next step is your own vendor toolchain with your own constraints. What this layer is good at is the class of bug that survives a green testbench, which is a large enough class to be worth a few seconds of every debug run.