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

  • How to Use This Course
  • Reading Paths
  • Concept Map
  • Meet DCRouter
  • Glossary
  • Part 0: What Verification Is8
  • Part 1: What Can Go Wrong11
    • A Taxonomy of Bugs
    • Specification Bugs
    • Corner Cases and Boundaries
    • Concurrency and Races
    • Integration and Interface Bugs
    • Configuration and Mode Bugs
    • Performance Bugs
    • Reset, Clock and Power Bugs
    • Where Bugs Hide
    • Classifying the Bug Zoo
    • Drills: What Can Go Wrong
  • Part 2: Specifications as Checkable Rules8
  • Part 3: Observability and Controllability7
  • Part 4: Stimulus11
  • Part 5: Checking11
  • Part 6: Coverage10
  • Part 7: Formal and Simulation10
  • Part 8: Verification Levels and Reuse8
  • Part 9: Planning and Risk9
  • Part 10: Emulation and Prototyping8
  • Part 11: Post-Silicon Validation8
  • Part 12: Bug Economics8
  • Part 13: Debug7
  • Part 14: Sign-Off7
  • Part 15: Verification in Context8
  • Part 16: Case Studies5
  • Part 17: Capstones5
  • Part 18: Interview Preparation6
Loading lesson

‹Part 1: What Can Go Wrong
  1. Topics
  2. First Principles of Verification Strategy
  3. Part 1: What Can Go Wrong
  4. Concurrency and Races

Part 1 · What Can Go Wrong · Senior (S)

Concurrency and Races

Hardware does everything at once, and many bugs need two events in the same cycle: a push and a pop, a grant and a release, a credit return and a send. Why tests that do one thing at a time never find them, simulated with a counter that drifts only under simultaneous traffic.

On this page

    Note

    Level: Senior (S) · Answers: What can go wrong?

    Before this: Corner Cases and Boundaries

    A directed test pushes three words into a FIFO, waits, then pops them. Another pushes, pops, pushes, pops. Both pass. In the full system, data streams through the FIFO with a push and a pop in almost every cycle, and after a few thousand cycles it reports itself full while holding a single word. The designer had written each case separately and never the case where both happen at once.

    Why do bugs that need simultaneous events escape tests, and how are they found?

    The obvious answer, and why it breaks

    The obvious tests exercise each operation and check its effect: push and see the count rise, pop and see it fall. Hardware is not a sequence of operations; in a single cycle, many things change at once. The logic for "push and pop together" is a separate case, sometimes a separate branch, sometimes a priority between two conditions that was chosen wrongly. Tests written one operation at a time never take that branch.

    The idea: list the events that can meet

    Events meeting in one cycle

    Typical mistake

    Push and pop on a FIFO

    Counted as a push (or a pop)

    A send and a credit return

    The return is lost (DCRouter BUG_9)

    A grant and the end of the previous packet

    The new owner starts before the old one finishes

    Tails finishing on several outputs at once

    Only one is counted (DCRouter BUG_11)

    A request arriving as a block goes to sleep

    The request is stranded

    A register write and a hardware update to the same field

    One silently wins

    Build it: a counter that drifts only under simultaneous traffic

    An occupancy counter whose {push, pop} = 11 branch adds one instead of staying put, next to a true occupancy for comparison. Test A pushes and pops in separate cycles; test B streams data through with both in the same cycle.

    tb.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
    // A FIFO occupancy counter with a race bug: when a push and a pop happen in the
    // same cycle, it adds one instead of staying put. Test A pushes three words, then pops
    // them, never both in one cycle: the count is right. Test B streams words through,
    // pushing and popping together every cycle: the count drifts upward although the
    // FIFO never holds more than one word. The checker compares count with the true
    // occupancy after each test.
    module tb;
      logic clk = 0;
      always #5 clk = ~clk;
      initial begin $dumpfile("wave.vcd"); $dumpvars(0, tb); end
    
      int cyc = 0;
      always @(posedge clk) cyc <= cyc + 1;
    
      logic       push = 0, pop = 0;
      logic [3:0] count = 0, occ = 0;          // count: the design's; occ: the truth
      always @(posedge clk) begin
        case ({push, pop})
          2'b10: count <= count + 4'd1;
          2'b01: count <= count - 4'd1;
          2'b11: count <= count + 4'd1;        // BUG: should stay the same
          default: ;
        endcase
        occ <= occ + (push ? 4'd1 : 4'd0) - (pop ? 4'd1 : 4'd0);
      end
      // test A: cycles 0-2 push, 3-5 pop.  test B: cycle 7 push, cycles 8-11 push and pop, cycle 12 pop
      always @(posedge clk) begin
        push <= (cyc <= 2) || (cyc >= 7 && cyc <= 11);
        pop  <= (cyc >= 3 && cyc <= 5) || (cyc >= 8 && cyc <= 12);
      end
      int a_ok = 0, b_bad = 0;
      always @(posedge clk) begin
        if (cyc == 6 && count == occ) a_ok = 1;
        if (cyc == 14 && count != occ) b_bad = 1;
      end
      initial begin
        #200;
        if (a_ok && b_bad) $display("PASS: separate pushes and pops kept the count right; simultaneous ones made it drift to %0d with the FIFO empty", count);
        else $display("FAIL: test A ok %0d, test B caught %0d", a_ok, b_bad);
        $finish;
      end
    endmodule

    Watch it run

    How to read it, slot by slot:

    • Slots 0 to 6, test A: three pushes then three pops, never together. count and occ agree at every slot: 1, 2, 3, 2, 1, 0.

    • Slot 7: test B's first push alone: both go to 1 at slot 8.

    • Slots 8 to 11: push and pop together every cycle. The true occupancy stays at 1; count climbs 2, 3, 4, 5.

    • Slot 12: the final pop leaves the FIFO empty, but count only falls to 4. A design using this count would report itself nearly full while empty.

    Finding concurrency bugs

    Approach

    How it creates simultaneous events

    Random timing

    Random gaps and delays make events coincide in many combinations (Part 4)

    Random back-pressure

    Stalling consumers at random times collides arrivals with departures

    Streaming traffic

    Full-rate traffic makes push and pop together the normal case

    Coverage crosses

    A bin for "push and pop in one cycle at each occupancy" shows whether it happened (Part 6)

    Formal

    Considers every combination of events in every cycle (Part 7)

    How real teams find them

    Practice

    Effect

    Randomised delays and back-pressure in every agent

    Simultaneous events become routine instead of rare

    Cross coverage of concurrent conditions

    Missing combinations are visible as holes

    Formal proofs of counters and credit loops

    Every simultaneous case checked, not sampled

    What breaks

    DCRouter's Bug Zoo contains four concurrency bugs, including this exact counter mistake inside its FIFO (BUG_2) and a credit return lost when it coincides with a send (BUG_9). The smoke test of lesson 0.7 catches BUG_2 by luck of its timing; BUG_9 only reduces DCRouter's credits, so the router keeps working, more slowly, and no data check ever fails. It is a concurrency bug that looks like a performance bug.

    Why this matters

    Senior lens. For every state-holding element, list the events that can update it and ask what happens when any two arrive in the same cycle. Each pair is a case the designer must have handled and the verification must reach. Random timing makes most pairs common; the rest need coverage crosses to prove they happened, or a formal check.

    Interview

    Asked: "Give an example of a concurrency bug and how you'd find it."

    Weak answer: A race condition in the testbench.

    Strong answer: A FIFO counter that handles push and pop in the same cycle as a push, so it drifts upward under streaming traffic and eventually reports full while nearly empty. Tests that push and pop in separate cycles never take that branch. I'd find it with streaming traffic and random back-pressure so pushes and pops coincide constantly, a coverage cross of push and pop together at each occupancy, a scoreboard or occupancy check that compares the count with the truth, and formally by proving the count always equals pushes minus pops.

    Follow-ups: (1) Why do directed tests miss it? (2) Which DCRouter bug looks like a performance problem?

    Check yourself Name two pairs of events in DCRouter that can happen in the same cycle.

    Any two of: a FIFO push and pop, a send and a credit return on one output, tails finishing on two outputs, a grant and a sleep decision, a register write and a counter increment.

    Check yourself Why can a concurrency bug look like a performance bug?

    If the race loses a resource (like a credit) instead of corrupting data, the design keeps working with less of it, so only throughput suffers.

    Key takeaways

    • Hardware changes many things per cycle; many bugs need two events in the same cycle.

    • Tests that do one operation at a time never reach those cases.

    • Random timing, back-pressure, coverage crosses and formal reach simultaneous events.

    Keep going

    Next: Lesson 1.5, Integration and Interface Bugs. Blocks that each pass, and fail together.

    Related topics

    • Part 1 overview: What Can Go Wrong

    Previous

    17 / 160

    Next: Integration and Interface Bugs

    Up next

    Up nextIntegration and Interface Bugs

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • A Taxonomy of Bugs
    • Specification Bugs
    • Configuration and Mode Bugs
    clkpushpopcount0123210123454occ012321010
    Simulation output: separate pushes and pops keep count equal to the true occupancy; simultaneous ones make count climb while the FIFO holds one word.