Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Part 0 · What Debugging Is6
  • Part 1 · Reproduce8
  • Part 2 · Observe9
  • Part 3 · Localise10
  • Part 4 · Hypothesise and Test6
  • Part 5 · Bug Classes16
  • Part 6 · Debug by Stage9
    • RTL Simulation
    • Formal Counterexamples as Traces
    • Gate-Level Simulation
    • Equivalence Failures
    • Emulation and FPGA Prototyping
    • The First Failing Test on Silicon
    • Silicon vs Simulation Correlation
    • Marginal and Environmental Failures
    • Moving the Failure to the Cheapest Stage
  • Part 7 · Hangs and Deadlocks7
  • Part 8 · Intermittent Failures7
  • Part 9 · Fix, Prove, Prevent7
  • Part 10 · Case Studies12
  • Part 11 · Debug as a Team5
  • Part 12 · Interview Prep5
Loading lesson

‹Part 6 · Debug by Stage
  1. Topics
  2. The Art of Hardware Debug
  3. Part 6 · Debug by Stage
  4. Marginal and Environmental Failures

Part 6 · Debug by Stage · Senior (S)

Marginal and Environmental Failures

Failures that come and go with voltage, frequency, temperature and the test pattern: map them as a shmoo, read the shape (a setup wall, a hold band, shifts with heat and switching), and measure the margin at the operating point. A timing-margin model swept like a shmoo gives real pass/fail grids at four conditions.

On this page

    Why this matters

    A part that fails only when hot, or only on one test, or only on some units, gets called a bad batch and shipped with a voltage bump that hides the cause. A shmoo turns "sometimes" into a map whose shape names the mechanism and whose distance from the operating point is the real margin.

    After this lesson you can: map a marginal failure over voltage, period and temperature, read a shmoo's shape as setup-type, hold-type or pattern-dependent, measure the margin at the operating point, and pick the next stage that has timing in it.

    Note

    Level: Senior (S) · Debug-loop step: Observe, Localise

    Before this: Timing-Only Bugs, The First Failing Test on Silicon

    Fails in the box, passes on the bench

    The parts passed production test at 25 C and nominal settings. In the field, units in a hot enclosure report corrupted results a few times a day. In the lab one test, a memory copy with heavy switching, fails on a few units even at room temperature, and a firmware engineer finds that raising the supply by 50 mV makes everything pass.

    Is it a design bug, a defective batch, or a design with no margin? And is the voltage bump a fix?

    What people usually do, and why it fails

    The RTL regression is rerun with the failing data and passes, because the logic is right. Then the failing units are called a bad batch and sent for failure analysis, which finds nothing, because nothing is broken. Then the voltage bump ships. It hides a setup problem at the cost of power and ageing, and if the real problem includes a hold path it makes that worse. Each failing condition gets its own bug report, and nobody sees that all of them are one picture.

    The method: map, read, measure, then localise

    1. Confirm it is marginal. Change one condition and watch the failure rate: voltage, frequency, temperature, the test. A rate that follows any of them is a margin question. A failure that follows none points elsewhere: Part 8 for intermittents.

    2. Map it. Run the failing test over a grid of supply voltage and clock period, a shmoo, at more than one temperature, on more than one unit. The bring-up course covers how a lab builds and automates one.

    3. Read the shape. A diagonal wall that moves to longer periods as voltage falls is setup-type: a path too slow. A band at high voltage or low temperature that fails at every period is hold-type: a path too fast for the clock skew. Holes and islands inside a passing region suggest noise, a resonance or a test that is itself marginal. Which bits fail and how the failure moves were covered in timing-only bugs.

    4. Compare shmoos. Across tests: a wall that moves with the test is power integrity (switching-heavy tests droop the supply). Across temperature: the setup wall moves with temperature, usually towards longer periods when hot; at low voltage in recent processes, temperature inversion can make cold the slow corner, so map both. Across units: a spread is the process; a single outlier is a defect candidate.

    5. Measure the margin. At the worst test and the worst corner, count the steps from the operating point to the wall. That number, not "it passes", is the result.

    6. Then localise the path. Move to a stage that has timing in it: static timing at the failing corner, gate-level simulation with the delay file (gate-level simulation), or path-delay tests on the tester.

    Do it: a timing-margin model swept like a shmoo

    No chip, chamber or tester is available here, so this is a model, and everything below is labelled as one. Each "die" of margin_unit has two paths. A setup path: a register, 0.96 ns of logic at 0.90 V and 25 C, and the next clock edge. A hold path: one flop to the next through 0.15 ns of logic, where the capturing flop's clock arrives 0.105 ns late. Every delay scales with an alpha-power law, slower at low voltage and when hot, and the setup path's local supply droops when many bits switch. The bench builds 81 dies per condition, nine voltages by nine periods, at four conditions, and prints each shmoo the way silicon gives it: pass or fail, and nothing else.

    margin_unit.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    `timescale 1ns/1ps
    // margin_unit: a timing model of two paths on one die at one supply voltage, temperature and
    // clock period. It is a model, not a netlist. Delays follow an alpha-power law,
    //   scale(V, T) = ((0.90 - 0.35) / (V - 0.35)) ** 1.3 * (1 + 0.0015 * (T - 25)),
    // so every path is slower at low voltage and when hot.
    //   setup path: register a, then 0.96 ns of logic (at 0.90 V, 25 C), captured by the next edge.
    //     Switching makes the local supply droop: V - 0.05 V * (bits of a that toggle) / 32.
    //   hold path: flop b1 to flop b2 through 0.15 ns of logic; b2's clock arrives 0.105 ns late
    //     (clock skew, kept fixed here), so a path that gets too fast races through.
    // NOISY = 0 counts a up (few bits toggle); NOISY = 1 flips almost every bit every cycle.
    module margin_unit #(parameter real V = 0.9, T = 25.0, PERIOD = 1.0, parameter bit NOISY = 0) (
      output bit done, output int unsigned setup_errs, hold_errs
    );
      localparam real SKEW = 0.105;
      function automatic real scale(input real v);
        return ((0.90 - 0.35) / (v - 0.35)) ** 1.3 * (1.0 + 0.0015 * (T - 25.0));
      endfunction
      function automatic logic [31:0] f(input logic [31:0] x); return x ^ {x[28:0], 3'b0}; endfunction
    
      logic clk = 1'b0, clk_late = 1'b0;
      initial begin #0.3; forever #(PERIOD / 2.0) clk = ~clk; end
      always @(clk) clk_late <= #(SKEW) clk;
    
      // Each launched value is kept with the time it reaches the capturing flop; a flop captures the
      // newest value that has arrived by its clock edge (a transport delay, the same in every simulator).
      logic [31:0] a = '0, pv [3], r = '0, want = '0;
      real         pt [3], bt [3];
      logic        b1 = 1'b0, bv [3], b2 = 1'b0, b2_exp = 1'b0;
      int unsigned n = 0;
      initial begin
        setup_errs = 0; hold_errs = 0; done = 1'b0;
        for (int k = 0; k < 3; k++) begin pv[k] = '0; pt[k] = -10.0; bv[k] = 1'b0; bt[k] = -10.0; end
      end
    
      function automatic logic [31:0] arrived_p(input real now);
        for (int k = 0; k < 3; k++) if (pt[k] <= now) return pv[k];
        return 'x;
      endfunction
      function automatic logic arrived_b(input real now);
        for (int k = 0; k < 3; k++) if (bt[k] <= now) return bv[k];
        return 1'bx;
      endfunction
    
      always @(posedge clk) begin : launch_and_capture
        logic [31:0] nxt;
        real d;
        r = arrived_p($realtime);                      // setup path: capture at this edge
        if (n > 4 && n < 200) begin
          if (r !== want)    setup_errs++;
          if (b2 !== b2_exp) hold_errs++;
        end
        nxt = NOISY ? ~a ^ 32'(n) : a + 32'd1;         // launch the next value
        d = 0.96 * scale(V - 0.05 * $countones(nxt ^ a) / 32.0);
        for (int k = 2; k > 0; k--) begin pv[k] = pv[k-1]; pt[k] = pt[k-1]; bv[k] = bv[k-1]; bt[k] = bt[k-1]; end
        pv[0] = f(nxt); pt[0] = $realtime + d;
        bv[0] = ~b1;    bt[0] = $realtime + 0.15 * scale(V);
        b2_exp = b1;                                   // b2 must take b1's value from before this edge
        want = f(nxt);                                 // the next edge must capture this launch
        a = nxt; b1 = ~b1;
        n++;
        if (n == 200) done = 1'b1;
      end
      always @(posedge clk_late) b2 = arrived_b($realtime);   // hold path: capture 0.105 ns late
    endmodule
    

    The shmoo at room temperature

    Terminal
    $ iverilog -g2012 -o s.vvp shmoo_tb.sv
    $ vvp -n s.vvp
    shmoo 0: 25 C, counting pattern   (* pass, . fail)
      period ns  0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7
      1.10 V     .   .   .   .   .   .   .   .   .
      1.05 V     *   *   *   *   *   *   *   *   *
      1.00 V     *   *   *   *   *   *   *   *   *
      0.95 V     *   *   *   *   *   *   *   *   *
      0.90 V     .   *   *   *   *   *   *   *   *
      0.85 V     .   .   .   *   *   *   *   *   *
      0.80 V     .   .   .   .   *   *   *   *   *
      0.75 V     .   .   .   .   .   .   .   *   *
      0.70 V     .   .   .   .   .   .   .   .   .
    ...

    Read it as the lab would, with no knowledge of the paths. Two failure regions, two shapes:

    • The lower left is a wall. As the voltage falls the first passing period moves right: 0.9 ns at 0.95 V, 1.2 ns at 0.85 V, 1.6 ns at 0.75 V. A failure that a longer period cures is a path that is too slow: setup-type.

    • The top row is a band. At 1.10 V the part fails at every period, including 1.7 ns, nearly twice the shortest period that passes one row below. A slower clock does not help, so the period is not in the failing check: hold-type, a path that got fast enough to race the clock skew.

    • The operating point (0.90 V, 1.0 ns) passes, with one step to the wall: 0.9 ns fails.

    The picture

    The 25 C shmoo of the model: setup failures form a wall in the lower left that moves to longer periods as voltage falls, hold failures fill the 1.10 V row at every period, and the operating point at 0.90 V and 1.0 ns sits one cell from the wall.

    The colours come from +WHY, which only a model can print: grey is the setup path, accent the hold path. On silicon you get the stars and dots, and the shape is how you tell them apart.

    Change the test, then the temperature

    Terminal
    $ vvp -n s.vvp
    ...
    shmoo 1: 25 C, switching pattern   (* pass, . fail)
      period ns  0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7
      1.10 V     .   .   .   .   .   .   .   .   .
      1.05 V     *   *   *   *   *   *   *   *   *
      1.00 V     *   *   *   *   *   *   *   *   *
      0.95 V     .   *   *   *   *   *   *   *   *
      0.90 V     .   .   *   *   *   *   *   *   *
      0.85 V     .   .   .   .   *   *   *   *   *
      0.80 V     .   .   .   .   .   .   *   *   *
      0.75 V     .   .   .   .   .   .   .   .   .
      0.70 V     .   .   .   .   .   .   .   .   .
    shmoo 2: 85 C, counting pattern   (* pass, . fail)
      period ns  0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7
      1.10 V     *   *   *   *   *   *   *   *   *
      1.05 V     *   *   *   *   *   *   *   *   *
      1.00 V     *   *   *   *   *   *   *   *   *
      0.95 V     .   *   *   *   *   *   *   *   *
      0.90 V     .   .   *   *   *   *   *   *   *
      0.85 V     .   .   .   .   *   *   *   *   *
      0.80 V     .   .   .   .   .   .   *   *   *
      0.75 V     .   .   .   .   .   .   .   .   *
      0.70 V     .   .   .   .   .   .   .   .   .
    shmoo 3: -40 C, counting pattern   (* pass, . fail)
      period ns  0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7
      1.10 V     .   .   .   .   .   .   .   .   .
      1.05 V     .   .   .   .   .   .   .   .   .
      1.00 V     *   *   *   *   *   *   *   *   *
      0.95 V     *   *   *   *   *   *   *   *   *
      0.90 V     *   *   *   *   *   *   *   *   *
      0.85 V     .   .   *   *   *   *   *   *   *
      0.80 V     .   .   .   *   *   *   *   *   *
      0.75 V     .   .   .   .   .   .   .   *   *
      0.70 V     .   .   .   .   .   .   .   .   *
    PASS: setup wall moves with voltage, temperature and pattern; the hold band ignores the clock period
    • Shmoo 1, same die, a switching-heavy test. The wall moves about one voltage step: at 0.90 V the first passing period is now 1.1 ns, so the operating point fails. Nothing about the logic changed; the supply droops when most bits switch. This is the scene's memory-copy test, and why one test fails at room temperature while others pass.

    • Shmoo 2, hot. The wall moves the same way, and the operating point fails again: the field failure. The hold band has gone, because hot paths are slow.

    • Shmoo 3, cold. The setup wall moves left (cold is fast in this model), and the hold band grows to two rows: 1.05 V now fails at every period. The voltage bump from the scene, 0.90 to 0.95 V, still passes cold; a second bump to 1.05 V would fail every cold unit.

    • Verilator 5.048 prints the same four grids, and the same +WHY labels.

    What the evidence says

    Condition

    0.90 V, 1.0 ns (operating point)

    0.1 ns faster (0.9 ns)

    50 mV lower (0.85 V)

    25 C, counting

    pass

    fail

    fail

    25 C, switching

    fail

    fail

    fail

    85 C, counting

    fail

    fail

    fail

    -40 C, counting

    pass

    pass

    fail; and 1.05 V fails (hold)

    One picture explains all three reports in the scene: there is no bad batch, the design has no setup margin at its worst test or its hot corner, and the voltage bump works for setup only because it stays below the hold band. The next stage is the one that has the paths: static timing at the hot, low-voltage corner with the switching test's droop, and gate-level simulation with the delay file on the paths it names. Only then do you choose between a slower clock, a higher voltage with its cost, and a fix to the path.

    Traps

    Common pitfall

    Raising the voltage until it passes. It moves the setup wall and the hold band in opposite directions. In the model 0.95 V cures the hot failure and 1.10 V fails every period at room temperature. Before a voltage change ships, shmoo it cold.

    Common pitfall

    One test's shmoo as the part's shmoo. The counting test says one step of margin; the switching test says none. Map the test that switches the most, the one that runs hottest, and the one the customer runs, and take the worst.

    Comparing a bench and a tester

    A shmoo from a bench board and one from a production tester can differ because the two set voltage at different points, measure temperature differently, or apply different patterns. Before reading a difference between them as a silicon effect, correlate the setups (ATE vs bench correlation). The same rule, that inputs must match before outputs are compared, is the subject of the correlation lesson.

    Why this matters

    Senior lens. Margin is a budget, and every team spends it without saying so: the timing sign-off corner, the supply's tolerance, the droop of the worst test, the temperature in the customer's box. A shmoo per new test at the corners, kept with the release, turns arguments about "marginal parts" into numbers. A hold band is the expensive case: no clock or voltage setting a customer will accept fixes it, so it means an engineering change or a respin, and it should be looked for on the first lots, cold, before anyone relies on a voltage bump.

    Interview

    Asked: "A few units fail one test only when they are hot, and raising the supply 50 mV fixes them. Is that a fix?"

    Weak answer: Yes, if the voltage bump makes all units pass, we can ship with the higher voltage and maybe screen the bad units.

    Strong answer: It is a workaround, and it tells me the failure is setup-type: a slow path that hot and low voltage make slower. Before accepting it I would shmoo that test against voltage and period at hot, room and cold, on several units, to find how far the operating point is from the wall and whether a hold band sits above the new voltage. I would also shmoo the most switching-heavy test, because supply droop moves the wall. Then I would localise the path with static timing at the failing corner and gate-level simulation with the delay file, and decide between a frequency, a voltage with its power and ageing cost, or a fix in the design.

    Follow-ups: (1) What would a failure at every frequency, only at high voltage and cold, tell you? (2) How would you tell a marginal design from a defective unit?

    Check yourself A new shmoo shows a small island of failures in the middle of the passing region, at one voltage and one period, on one unit. What do you check before reading it as a timing effect?

    Repeat it: an island that moves or vanishes on a rerun is noise in the setup or a test that is itself marginal (a timeout, a poll that races). Then check whether that voltage and period put a clock or a supply near a resonance or a beat with another clock on the board. A timing path gives a wall or a band, not an island, so an island is the board, the test or the environment until shown otherwise.

    Check yourself Ten units give ten shmoos. Nine have their wall within 20 mV of each other; one has it 80 mV higher. What does that suggest, and what next?

    The nine show the process spread of a design with some margin; the outlier suggests a defect or a local weakness on that one die, not a design problem. Compare which test and which bits fail first on the outlier against the others, then run path-delay or scan-based tests on it to find the slow path, and send it for failure analysis with that path named (root cause and FA hand-off).

    Remember

    • A wall that moves with the clock period is setup-type. A band at high voltage or cold that ignores the period is hold-type. Neither is a logic bug.

    • A shmoo belongs to one test at one temperature. Switching-heavy tests and temperature both move the wall, so map the worst test at the worst corner.

    • Ask how far the operating point is from the wall, not whether it passes. One step of margin at 25 C can be none when hot.

    Rule of thumb: a failure that moves with voltage, frequency or temperature is a margin question until a shmoo says otherwise.

    How this was checked

    shmoo_tb.sv as shown, 2026-10-18: iverilog -g2012 -o s.vvp shmoo_tb.sv, vvp -n s.vvp (Icarus Verilog 13.0, 1.0 s) prints the four shmoos shown and PASS; vvp -n s.vvp +WHY labels each failure S or H. verilator --binary --timing --assert -Wno-fatal --top-module shmoo_tb (Verilator 5.048, 21 s build) prints identical grids for both runs.

    Readings from the grids: at 25 C with the counting pattern the operating point (0.90 V, 1.0 ns) passes and 0.9 ns fails; with the switching pattern, and at 85 C, 1.0 ns fails at 0.90 V. 1.10 V fails at every period at 25 C and -40 C (hold, per +WHY), 1.05 V too at -40 C; at 85 C 1.10 V passes.

    Limits: everything here is a model. Delays follow an alpha-power law with made-up constants, the supply droop is a linear function of switching, the skew is fixed, and each die is one setup path and one hold path. It shows how shmoo shapes arise and how to read them; it measures no real process, and no tester, chamber or chip was used. The lab procedure is in the bring-up course.

    Keep going

    • Interview: run a mock interview on this topic

    Related topics

    • Part 6 · Debug by Stage

    • Bring-up: building and reading shmoo plots

    • Bring-up: timing and voltage margin analysis

    • Bring-up: intermittent and marginal failure triage

    • Timing-only bugs

    Previous

    63 / 107

    Next: Moving the Failure to the Cheapest Stage

    Up next

    Up nextMoving the Failure to the Cheapest Stage

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • RTL Simulation
    • Formal Counterexamples as Traces
    • Gate-Level Simulation