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
    • DPI-C: Calling C from SystemVerilog
    • bind: Attaching Verification to RTL
      • Bind Fundamentals
      • Writing Assertion Modules for bind
      • Bind File Organization
      • Reusable Checker Libraries
      • bind Debug & Limitations
    • Macros, Defines & Compilation
    • Plusargs, Files & Runtime Configuration
    • Simulation Performance & TB Memory
    • RTL/TB Boundaries, Races & Timing
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹bind: Attaching Verification to RTL
  1. Topics
  2. SystemVerilog
  3. Advanced Language & Integration
  4. bind: Attaching Verification to RTL
  5. Bind Fundamentals

Part 7 · Advanced & Integration · Intermediate

Bind Fundamentals

Bind a checker into RTL without touching it: targets, port maps, and elaboration.

On this page

    The bind construct instantiates a verification module inside an RTL module without editing the RTL source. The bound instance elaborates as a child of the target scope, seeing the target's ports and internal signals.

    That makes bind the standard delivery mechanism for assertion checkers, protocol monitors, and coverage collectors on design code that DV does not own. The next lesson, Writing Assertion Modules for bind, covers what a bind-safe module looks like.

    Check yourself Why does DV attach checkers with bind instead of editing assertions into the RTL?

    Three reasons: the RTL files stay untouched and synthesis-clean, the checkers live under DV ownership and review, and the bound instance still sees internal signals that a testbench-side checker could only reach through fragile hierarchical paths.

    What bind does

    A bind statement names a target, a checker module to insert, an instance name for the copy, and a port map. Ports connect by name to signals visible inside the target's scope, ports and internal signals alike.

    Targeting the module name binds the checker into every instance of that module. Targeting a specific instance path binds only that one copy, for instances that are configured differently or singly interesting.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // snippet
    // By module: every fifo_stub in the design gets a checker.
    bind fifo_stub fifo_bound_checks #(.DEPTH(DEPTH)) chk (.*);
    
    // By instance: only the command FIFO inside the DMA gets one.
    bind top.u_dma.u_cmd_fifo fifo_bound_checks #(.DEPTH(8)) chk (
      .clk(clk), .rst_n(rst_n), .push(push), .pop(pop),
      .full(full), .empty(empty), .count(count)
    );

    .* works when checker port names match target signal names exactly. Explicit maps survive renames better and make the connection auditable, so prefer them outside throwaway binds.

    What elaboration produces

    After elaboration the bound instance is a real child of the target, present under the target's path in every instance for a module bind. It elaborates almost as if the instantiation line were the last statement inside the target: visibility follows the target's scope, not a literal inline copy.

    Diagram
    ELABORATED HIERARCHY
    
      source: bind fifo_stub fifo_bound_checks #(...) chk (...);
    
      top
       |- u_dma
       |   |- u_cmd_fifo (fifo_stub)
       |   |   |- ...rtl contents...
       |   |   └- chk (fifo_bound_checks)   <- inserted by bind
       |   └- u_data_fifo (fifo_stub)
       |       |- ...rtl contents...
       |       └- chk (fifo_bound_checks)   <- every instance
    
      Wave path:  top.u_dma.u_cmd_fifo.chk.a_count_range
      Scope:      chk sees fifo_stub's clk, push, count, ... by name

    Parameters pass through normally, so one checker scales across differently sized instances. A bound unit can be a module, interface, program, or checker, and one target can receive several binds under distinct instance names.

    Common mistakes

    Common pitfall

    A module bind multiplies: 200 FIFO instances means 200 checkers. That is fine for assertions and costly for heavy covergroups, so keep bound logic light.

    Interview

    Expect: “attach a checker to RTL you may not edit.” Name the four pieces (target, checker module, instance name, port map) and say where the instance appears in waves: under the target's path, never under the testbench.

    Check yourself A module bind targets fifo_stub and the design has three instances. How many checkers elaborate, and where do they appear?

    Three, one per instance. Each appears as chk under its own target instance, for example top.u_dma.u_cmd_fifo.chk.

    Check yourself The RTL renames count to occ_q. Which file do you fix, and how does the failure show up?

    The DV bind file. Elaboration reports a signal-not-found at the bind line, which is routine maintenance after RTL drops, never a reason to keep legacy names in RTL.

    Testbench

    A two-instance FIFO stub with a bound occupancy checker. Traffic stays legal, so a silent assertion run plus a reference-model count check is the pass. The testbench also reads u_small.chk.DEPTH and u_big.chk.DEPTH: those paths exist only because the bind put a checker under each instance, so the bench fails to elaborate without it.

    fifo_stub.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
    // engine: verilator
    timeunit 1ns; timeprecision 1ps;
    
    // A module bind elaborates one checker per instance; each tracks its own target.
    module fifo_stub #(parameter int DEPTH = 8) (
      input  logic clk, rst_n,
      input  logic push, pop,
      output logic full, empty,
      output logic [$clog2(DEPTH):0] count
    );
      always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) count <= '0;
        else case ({push && !full, pop && !empty})
          2'b10:   count <= count + 1'b1;
          2'b01:   count <= count - 1'b1;
          default: count <= count;
        endcase
      end
      assign full  = (count == DEPTH);
      assign empty = (count == '0);
    endmodule
    
    module fifo_bound_checks #(parameter int DEPTH = 8) (
      input logic clk, rst_n,
      input logic push, pop, full, empty,
      input logic [$clog2(DEPTH):0] count
    );
      default clocking cb @(posedge clk); endclocking
      default disable iff (!rst_n);
    
      a_no_push_full : assert property (full |-> !push || pop)
        else $error("push into full fifo");
      a_no_pop_empty : assert property (empty |-> !pop)
        else $error("pop from empty fifo");
      a_count_range  : assert property (count <= DEPTH);
    endmodule
    
    bind fifo_stub fifo_bound_checks #(.DEPTH(DEPTH)) chk (
      .clk(clk), .rst_n(rst_n), .push(push), .pop(pop),
      .full(full), .empty(empty), .count(count)
    );
    

    Related topics

    • Writing Assertion Modules for bind

    • bind Debug & Limitations

    Previous

    190 / 259

    Next: Writing Assertion Modules for bind

    Up next

    Up nextWriting Assertion Modules for bind

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Bind File Organization
    • Reusable Checker Libraries
    • bind Debug & Limitations