The SystemVerilog bind command allows for adding new functionality to a module. Typically, it is used to add new checking to a RTL module.
I wrote the example code (available on GitHub here) below to demonstrate a feature of bind that allows the binded module to parameterize itself based on where it is being used. When you think about what bind is actually doing, it starts to make sense.
1 // DUT 2 module dut #(parameter X=3, parameter Y=2, parameter Z=1, parameter NAME="DEFAULT") (); 3 initial begin 4 $display("dut %s value of X Y Z is: %d", NAME, X, Y, Z); 5 end 6 endmodule 7 8 // BINDED TO DUT : BDUT 9 module bdut #(parameter X=4, Y=4, Z=4, NAME="DEFAULT") (); 10 logic [X:0] bus; 11 initial begin 12 $display("bdut %s value of X Y Z is: %d %d %d", NAME, X, Y, Z); 13 end 14 endmodule 15 16 // TOP LEVEL 17 module top(); 18 dut#(.NAME("dut1")) dut1(); 19 dut#(.NAME("dut2"),.X(100)) dut2(); 20 initial begin 21 #1; 22 $finish(); 23 end 24 endmodule 25 26 // BIND CONNECTING PARAMETERS FROM DUT INSTANCES TO BDUT 27 bind dut bdut#(.X(X), .Y(Y), .Z(), .NAME(NAME)) a_inst();
If you take line 27 and strip off the first two arguments you can imagine pasting the rest of the line into "dut"; there, all of the parameter customization would flow into the instantiation of "bdut". When you look at the bind statement (line 27) it wouldn't make any sense where it is. All of the parameters being used aren't defined on line 27, but when the bind is activated it now has the scope to parameterize itself.
One special case to note is that on line 27 the ".Z()" parameterization is left empty. This allows for the defaults for "bdut" to take over. Line 10 creates a "logic [X:0] bus" in "bdut" based off of the parameterization. This could be used to make a parameterized coverpoint or other functionality needing parameterization.
The output of running the example code is below.
dut dut1 value of X Y Z is: 3 2 1 bdut dut1 value of X Y Z is: 3 2 4 dut dut2 value of X Y Z is: 100 2 1 bdut dut2 value of X Y Z is: 100 2 4