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

  • Start Here6
  • SystemVerilog Language Foundations28
  • Object-Oriented SystemVerilog for Verification30
  • Constraint Randomization — Interview-Critical Deep Dive36
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
    • Senior Debug Playbook
    • Reviewing Verification Code
      • Reviewing Transactions & Constraints
      • Reviewing TB Components
      • Reviewing Assertions & Coverage
      • Review Process & Checklist
    • Verification Strategy: Spec to Sign-Off
    • SystemVerilog Interview Q&A Bank
    • Capstone: Verify a Parameterized FIFO
  • Principal-Level Verification28
Loading lesson

‹Reviewing Verification Code
  1. Topics
  2. SystemVerilog
  3. Senior & Interview Preparation
  4. Reviewing Verification Code
  5. Reviewing TB Components

Part 8 · Senior & Interview Prep · Intermediate

Reviewing TB Components

Review drivers, monitors, and scoreboards for timing discipline, reset handling, and honest drain.

On this page

    One source of truth each

    Most component defects break one of two rules. Each component may observe exactly one source of truth, and each follows exactly one timing discipline.

    Component

    Source of truth

    Timing rule

    Driver

    The sequencer item

    Drive off the edge; hold valid until the handshake

    Monitor

    The pins only

    Sample the full legal timing range, not current RTL habits

    Scoreboard

    The monitor stream

    Drain means empty queue and nonzero compares

    A monitor that reads driver state verifies the testbench against itself. Checking dies and the regression stays green.

    Worked review: a rushing driver

    The listing below is not run in this course's checks: it needs the UVM library, which neither course tool (Icarus 13, Verilator 5.048) runs here.

    design.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
    // not-run: needs the UVM library (uvm_driver, sequencer port); neither Icarus 13 nor Verilator 5.048 here runs uvm_pkg
    class bus_driver extends uvm_driver #(bus_txn);
      virtual bus_if vif;
      `uvm_component_utils(bus_driver)
    
      task run_phase(uvm_phase phase);
        forever begin
          seq_item_port.get_next_item(req);
          fork
            drive_one(req);
          join_none
          seq_item_port.item_done();
        end
      endtask
    
      task drive_one(bus_txn t);
        @(posedge vif.clk);
        vif.valid = 1;                 // blocking drives
        vif.addr  = t.addr;
        vif.write = t.write;
        while (vif.ready !== 1)
          @(posedge vif.clk);
        vif.valid = 0;
      endtask
    endclass
    1. BLOCK — item_done fires before any driving. The sequencer handshake becomes meaningless and transactions overlap on shared pins. Completion is reported only after the drive finishes.

    2. BLOCK — blocking drives on the active edge. Whether the DUT samples old or new values is scheduler-dependent. All pin access goes through the clocking block or an equivalent off-edge discipline.

    3. BLOCK — no reset branch. On mid-burst reset the driver holds valid through reset. Every driver needs a reset path that aborts the in-flight transaction and rests the pins.

    4. BLOCK — ready sampled raw, not through the clocking block. The sample lands in the wrong region relative to the DUT update. It is the same race family as the drives.

    5. NOTE — no timeout on the ready wait. A dead DUT turns this into an unattributed hang. A bounded wait names the culprit at once.

    6. NOTE — no transaction logging. The driver stays invisible to the debug layers the team relies on.

    Common pitfall

    Reviewing drive timing against what the current RTL happens to do. The protocol's legal range is the reference: zero-wait responses, back-to-back bursts, and mid-burst reset.

    A disciplined driver and testbench

    The testbench below is plain SystemVerilog and runs in both course tools. A small slave stalls one cycle in four, and a stall hook forces one reset to land mid-send.

    The driver holds valid until the handshake, aborts cleanly on reset, and bounds every wait at 32 cycles. The monitor watches pins only, and the end of test checks both drain gates.

    Watch valid against ready. The request waits two slots before the grant arrives.

    • Slot 0: idle, valid 0 and ready 0 with data 0x0.

    • Slot 1: valid rises with data 0xa1 while ready stays low.

    • Slot 2: still waiting; valid holds because the handshake has not happened.

    • Slot 3: ready rises, so this slot is the handshake both sides count.

    • Slot 4: valid and ready rest at 0 with data 0x0.

    tiny_slave.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    module tiny_slave (
      input  logic       clk,
      input  logic       rst_n,
      input  logic       stall,   // test hook: hold ready low on demand
      input  logic       valid,
      output logic       ready,
      input  logic [7:0] addr,
      output logic [7:0] rdata
    );
      logic [1:0] cnt;
      assign ready = (cnt != 2'd2) && !stall;
      assign rdata = addr + 8'd1;
      always @(posedge clk or negedge rst_n) begin
        if (!rst_n) cnt <= 2'd0;
        else        cnt <= cnt + 2'd1;
      end
    endmodule
    

    A driver that drops a transaction early would trip the compared != N_TXNS gate above. That is the whole point of gating passes on activity instead of on zero complaints.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // snippet
    fork begin : drive_or_reset
      fork
        drive_one(req);
        @(negedge rst_n);      // reset wins the race
      join_any
      disable fork;
    end join
    // The outer fork...join isolates the disable: without it, disable fork
    // can kill sibling threads elsewhere in the same parent process.

    Common mistakes

    • Approving a monitor that reads driver state temporarily until pins are ready. Temporary becomes permanent and checking turns circular.

    • Overlooking a fork...join_none before item_done in a request loop. Transactions overlap on shared pins and corrupt each other.

    • Letting unbounded waits through review. Each one is a future hang with no name on it.

    • Gating the pass on zero mismatches alone, with no activity count beside it.

    Interview

    Likely question: “the regression is green but the DUT is broken — how”. Strong answers reach for the monitor source of truth and the drain gates before anything else.

    Check yourself A driver reports completion right after forking the pin wiggle. Which two failures follow?

    The sequencer believes the item finished before it started, and the next item overlaps it on the same pins. Pin traffic corrupts while the handshake claims success.

    Check yourself End of test finds the expected queue empty but the compare count at zero. Pass or investigate?

    Investigate. An empty queue with zero compares is consistent with nothing ever arriving. Both gates must hold together.

    Related topics

    • Monitors and scoreboards

    • Synchronization

    Previous

    216 / 259

    Next: Reviewing Assertions & Coverage

    Up next

    Up nextReviewing Assertions & Coverage

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Review Process & Checklist
    clkvalidreadydata0a10
    One stalled handshake: valid waits for ready, then both rest