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

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Puzzle Bank
  • SystemVerilog Language Puzzles25
  • Difficulty Guide
  • Full Topic Map
  • Interview-Day Tips
  • Study Route: One Week Before the Interview
  • Study Route: Two Weeks
  • Study Route: Four Weeks (Full Course)4
  • OOP & Testbench Puzzles25
  • Concurrency & Timing Puzzles25
    • Event Scheduling Puzzles
    • Race Condition Puzzles
    • Clocking Block Puzzles
      • Why Every Sample Is One Cycle Old
      • Interpreting |=> ##1 in Clocking Domain
      • disable fork Kills Unrelated Background Threads
      • input #0 vs input #1step Snapshot
      • Nonzero Input Skew Looks Back in Time
      • Mixing Direct Drive and cb Drive
    • Semaphore & Mailbox Puzzles
    • Concurrency & Timing Puzzles: Tricky Q&A
  • Randomization & Constraint Puzzles25
  • SVA Assertion Puzzles25
  • Functional Coverage Puzzles25
  • Logic & Aptitude Puzzles25
  • Scenario & Debug Puzzles25
  • UVM Testbench Puzzles25
  • Clock, Reset & CDC Puzzles25
  • Bus and Interface Protocol Puzzles25
  • Interview Prep: Puzzle Rounds7
  • DV Puzzle Cheatsheet
Loading lesson

←Clocking Block Puzzles
  1. Topics
  2. DV Interview Puzzles
  3. Concurrency & Timing Puzzles
  4. Clocking Block Puzzles
  5. Mixing Direct Drive and cb Drive
On this page

    VLSI DV Interview PuzzlesAll levels

    Mixing Direct Drive and cb Drive

    Identify which line introduces race potential and why the DUT's view of req can change between tools or after a source reorder.

    Puzzle

    Difficulty: Hard · Puzzle 6 of 6 · Topic: Clocking Block Puzzles

    Identify which line introduces race potential and why the DUT's view of req can change between tools or after a source reorder.

    Code

    ifc.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
    `timescale 1ns/1ns
    interface ifc(input bit clk);
      logic req, grant;
      clocking cb @(posedge clk);
        default input #1step output #0;
        input grant;
        output req;
      endclocking
    endinterface
    
    module tb;
      bit clk = 0;
      ifc vif(clk);
      always #5 clk = ~clk;
    
      always @(posedge clk) vif.grant <= vif.req;
    
      initial begin
        vif.req = 0;
        @(posedge clk);
        vif.req = 1;            // direct blocking drive in Active
        @(posedge clk);
        vif.cb.req <= 0;        // clocking-block drive
        repeat (2) @(posedge clk);
        $finish;
      end
    endmodule

    Hint

    A blocking write in Active at the clock edge competes with every Active-region reader of that edge.

    Step-by-step solution

    Diagram
    1) `vif.req = 1` runs in the Active region of t=5, the same region and edge in which the DUT executes vif.grant <= vif.req. Which runs first is not defined, so the DUT captures 0 or 1 at t=5.
    2) Demonstrated with a plain version of the same pattern (no clocking block): in Icarus swapping the source order of the initial and the always changes the value seen at t=15 (grant=1 vs grant=0); Verilator happened to give 1 both times.
    3) `vif.cb.req <= 0` is a Re-NBA drive, strictly after all Active reads of that edge, so it is deterministic.
    4) Not verified by execution: Verilator's clocking-block model did not apply the cb drive, so the cb half is reasoning from the LRM.
    5) Rule: one driver discipline per signal; all drives through the clocking block.

    Answer

    Answer: The direct `vif.req = 1` is the racy line. It writes in Active at the edge the DUT samples, so the DUT may see 0 or 1 on that edge; the clocking-block drive does not race.

    How this was checked

    Checked by running the code in Icarus Verilog 13 and Verilator 5; the printed output supports the answer above. Plain-signal version of the race: with the drive written before the always block, Icarus captures req=0 at t=5. Same code with the two blocks swapped: Icarus now captures req=1 at t=5, so the order of Active-region processes changes the DUT result. Verilator happens to pick one order for both layouts; the LRM defines neither, so never depend on it.

    Why candidates get it wrong

    Mixing styles is the trap: a helper task that bypasses the clocking block reintroduces exactly the race the clocking block was added to remove.

    Interviewer follow-up

    How would you enforce cb-only driving at compile time in your interface API? Model answer: expose the interface to the testbench through a modport that lists only the clocking block (modport drv (clocking cb);), so vif.req cannot be named and a direct write is a compile error. (Reasoning from the LRM; not tool-verified here.)

    Say it out loud

    The racy line is the direct write to req, because it runs in the Active region of the same edge where the DUT reads it, and their order is not defined. So the DUT may see 0 or 1, and the answer can change between tools or after a source reorder. The clocking-block drive lands after all the Active reads, so it does not race. The trap is mixing the two styles, for example a helper task that bypasses the clocking block; I would check that every drive of the signal goes through it.

    Related topics

    • Clocking Blocks as the Cure

    • Driving & Sampling via Clocking Blocks

    • Anatomy of a TB/RTL Race

    • Back to Clocking Block Puzzles

    • Concurrency & Timing Puzzles section

    Previous

    78 / 293

    Next: Semaphore & Mailbox Puzzles

    Up next

    Up nextSemaphore & Mailbox Puzzles

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Why Every Sample Is One Cycle Old
    • Interpreting |=> ##1 in Clocking Domain
    • disable fork Kills Unrelated Background Threads