The first dies run the stream-signature test. Each 64-word window of the stream is folded into a 32-bit signature, a MISR, which software reads at the end. Simulation of the same test gives eight signatures. Silicon gives eight different ones. The RTL team says simulation is the reference and the silicon is broken; the lab says silicon is what the customer gets and the model is wrong.
Both cannot be right, and both may be wrong. Which do you believe, and how do you find out?
Each side defends its instrument. The RTL team reruns the simulation, gets the same answer, and calls that proof. The lab runs the test on the same die again, gets the same answer, and calls that proof. Neither repeat adds information, because each repeats its own inputs. Then the debate moves to a single bit of evidence, the final signature matches or it does not, which cannot say where the two runs parted.
The question is not which instrument is real. Both are. Simulation says what the RTL does with the bench's inputs. Silicon says what one die did with the lab's inputs. The specification says what should happen. A disagreement lives in a difference between those: the inputs, the model, or the die.
Align the inputs first. Configuration after boot, firmware version, clock frequencies and their ratio, reset sequence, test version, the netlist or RTL version behind the simulation. Read the chip's registers through the debug port and set the simulation up from that dump, rather than from what the bench assumes.
Compare at the finest grain both sides can give. Per-window signatures, counters, a trace of one interface. The first window that differs is silicon's first wrong cycle, and everything before it is cleared.
Change the die before you change the design. A difference on every die is the design or the model. A difference on one die is that die: a defect, or a margin problem if it moves with voltage, frequency or temperature (marginal failures).
Know each model's blind spots. Simulation can disagree with silicon and be the one that is wrong (the table below). Silicon can mislead too: a bad socket, a marginal supply, a test program that differs from the simulated one.
Decide what each source is trusted for. Silicon is the truth about what this die did. Simulation, once correlated, is the truth about what the RTL specifies for those inputs. The specification decides which of them is the bug.
Where simulation can be the wrong one | What silicon does instead |
|---|---|
An unknown (X) or an uninitialised flip-flop | a definite 0 or 1, different per die and per power-up |
A two-state simulator starting flops at 0 | random power-up values; a bug that needs a nonzero value appears only on silicon |
Zero-delay logic | real path delays, setup and hold, droop |
Behavioural models of memories, PLLs, analogue or hard IP | the real block, with behaviour the model left out |
The RTL, after an engineering change made in the netlist | the changed netlist |
Differential debugging shows the first two rows on dbglab: the same seed gives X in one simulator, a pass in another and a random wrong value with random start-up values.
On the debug loop this is Observe and Localise across two instruments: the comparison is the observation, and the first differing window is the localisation.
The bench runs one test, 512 random words in eight windows, through four copies of the signature block. sim is the RTL as the bench sets it up. die_a and die_b are models of two silicon dies: both run boot code that sets a configuration bit, and die A also has a modelled physical defect, a bit that flips on certain words, which no simulation of the RTL can contain. sim_si is the RTL set up from die A's register dump. The bench prints the comparisons in the order the method makes them.
`timescale 1ns/1ps
// sig_engine: folds a stream of words into a 32-bit signature (a MISR), one signature per window
// of 64 words, restarted at each window, so each window can be compared on its own. A config
// register, CFG.swap (reset value 0), byte-swaps each word first.
// FLAW = 1 is a model of a physical defect on one die (for example a coupling fault): when a word's
// top byte is FF, bit 13 of the next signature flips. The RTL has FLAW = 0; no simulation of the
// RTL can show it.
module sig_engine #(parameter bit FLAW = 0) (
input logic clk, rst_n,
input logic cfg_we, cfg_swap, // config write port (software or boot code)
input logic in_valid,
input logic [31:0] in_data,
output logic swap_q, // config readback (the debug port reads it)
output logic win_valid, // a window's signature is ready
output logic [31:0] win_sig
);
logic [31:0] sig, w, nxt;
logic [5:0] cnt;
assign w = swap_q ? {in_data[7:0], in_data[15:8], in_data[23:16], in_data[31:24]} : in_data;
assign nxt = ({sig[30:0], sig[31] ^ sig[21] ^ sig[1] ^ sig[0]} ^ w)
^ ((FLAW && in_data[31:24] == 8'hFF) ? 32'h0000_2000 : 32'h0);
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) begin swap_q <= 1'b0; sig <= '0; cnt <= '0; win_valid <= 1'b0; win_sig <= '0; end
else begin
if (cfg_we) swap_q <= cfg_swap;
win_valid <= 1'b0;
if (in_valid) begin
cnt <= cnt + 6'd1;
if (cnt == 6'd63) begin win_sig <= nxt; win_valid <= 1'b1; sig <= '0; end
else sig <= nxt;
end
end
endmodule
$ iverilog -g2012 -o c.vvp corr_tb.sv
$ vvp -n c.vvp
step 1: simulation against die A, same test
window sim die A
0 2b03e740 7102b0ae DIFFERENT
1 c9eb1a70 6c06bc36 DIFFERENT
2 463494a0 176feeea DIFFERENT
3 bb6e0530 90e6bb70 DIFFERENT
4 bd9364d1 306686d5 DIFFERENT
5 ea7a1708 32289b39 DIFFERENT
6 e9c17833 8806cd87 DIFFERENT
7 dbffc3cf 11cf7efb DIFFERENT
step 2: config readback through the debug port: sim CFG.swap=0, die A CFG.swap=1All eight windows differ, from window 0. A difference that starts at the first observation and never stops is the signature of different inputs or setup, not of a bug that happens during the test. So before reading a single signature, read the configuration: die A has CFG.swap = 1, written by its boot code, and the simulation left it at its reset value of 0. The bench never ran the boot code.
step 3: simulation set up from die A's register dump, against die A
window sim_si die A
0 7102b0ae 7102b0ae same
1 6c06bc36 6c06bc36 same
2 176feeea 176feeea same
3 90a6bb71 90e6bb70 DIFFERENT
4 e6bd49e9 306686d5 DIFFERENT
5 32289b39 32289b39 same
6 bed01648 8806cd87 DIFFERENT
7 11ce7efb 11cf7efb DIFFERENT
step 4: the same against die B
window sim_si die B
0 7102b0ae 7102b0ae same
1 6c06bc36 6c06bc36 same
2 176feeea 176feeea same
3 90a6bb71 90a6bb71 same
4 e6bd49e9 e6bd49e9 same
5 32289b39 32289b39 same
6 bed01648 bed01648 same
7 11ce7efb 11ce7efb sameStep 3. With the simulation set up from die A's dump, windows 0, 1, 2 and 5 match exactly: the setup explained them completely. Windows 3, 4, 6 and 7 still differ, and the first is window 3: words 192 to 255.
Step 4. Die B, same boot code, matches the simulation in every window. So the RTL and its simulation agree with one die for this test, and the difference belongs to die A.
step 5: words with top byte FF in each window of the captured input: 0 0 0 1 1 0 1 1
summary: sim vs A 8 of 8 windows differ; sim_si vs A 4 (windows 3 4 6 7); sim_si vs B 0
PASS: the setup explained every difference but 4 windows; those differ only on die AWindows 3, 4, 6 and 7 each contain a word whose top byte is FF, and the matching windows contain none. The bench can print this because it knows the defect model; in a lab you find such a feature by running the differing windows' words as short tests and halving them, the bisection in stimulus of silicon. A pattern-dependent difference on one die, absent on another, is a failure-analysis case with the pattern named, or a margin question if it moves with voltage and temperature.
Which to believe was never the question. For what die A did, believe die A: its signatures repeat and they are the customer's result. For what the design should do with these inputs, believe the simulation, now that its inputs match and a second die agrees with it. Every window differed because of the bench; the four that still differ without it belong to one die. Nobody needed to change the RTL, and nobody needed to argue.
A simulation is golden only for what it models. A two-state simulator that starts every flip-flop at 0 will pass a design that reads an unreset register, and silicon, starting at random values, will fail it, differently on every power-up. When silicon fails and simulation passes, check the model's blind spots before the silicon.
An engineering change made in the netlist after the RTL froze, a test program edited for the tester, or a boot ROM built from a newer branch all give "silicon disagrees with simulation" with no bug in either. Put the version of every input in the comparison, as a replay record does for a simulation.
A difference from the first observation on every die is still an input or a model difference, not a bug during the test. Check what the register dump does not cover: the clock ratio, the reset sequence, the stimulus source (is the test program on the tester the one that was simulated?), and the version of the netlist behind the simulation. Then compare something simpler than the signature, such as the first few words of a trace, to see whether the inputs or the block's output differ first.
A value that changes with every power-up and every die points at state that is never initialised before it is read. A two-state simulator that starts flip-flops at 0 hides it. Rerun with unknown or random initial values, X in a four-state simulator or random start-up values in a two-state one; a failure that appears only then confirms the class, and the unreset registers read before being written are the suspects.
corr_tb.sv as shown, 2026-10-18: iverilog -g2012 -o c.vvp corr_tb.sv, vvp -n c.vvp (Icarus Verilog 13.0): steps 1 to 5 as shown and PASS; sim against die A, 8 of 8 windows differ; after the register dump, 4 (windows 3, 4, 6 and 7); against die B, 0. verilator --binary --timing --assert -Wno-fatal --top-module corr_tb (Verilator 5.048) prints the same lines.
Limits: both dies are models written for this page. Die A's defect is a modelled bit flip on words whose top byte is FF; die B is the RTL. The boot code is two lines of the bench. No chip, tester or debug port was used. Step 5 counts the trigger words because the bench knows the model; in a lab that feature has to be found, for example by running the differing windows' words as short tests.