最早接触 bind 关键字是在assertion 当中,将assertion 与 dut 进行绑定连接,如下例子:
- bind cpu fpu_props fpu_rules_1(a,b,c);
- //cpu 是module 名字
- //fpu_props 是内部包含 property 以及断言的模块,可以是 module 或者 program 甚至 interface
- //fpu_rules_1 是 fpu_props 的实例名
- //括号中的信号 a b c 是 cpu 的端口信号,并且连接到 fpu_props 的对应端口
来看下面一个将 interface bind 到 module 的例子:
- interface range (input clk,enable, input int minval,expr);
- property crange_en;
- @(posedge clk) enable |-> (minval <= expr);
- endproperty
- range_chk: assert property (crange_en);
- endinteface
-
- bind cr_unit range r1(c_clk,c_en,v_low,(in1&&in2));
可以看到,包含断言的 interface ,其端口信号的方向均为 input ,也就是说 property 中包含的信号都是从 interface 的外部给进来的;
实际上, bind 不仅仅 可以进行 断言 与 dut 之间的连接,两个 module 之间也能进行连接,如下面例子:
有 dut.v :
- module dut(clk, rst_n, vld, rdy, data);
- input clk;
- input rst_n;
- input vld;
- output reg rdy;
- output reg[31:0] data;
-
- bit[31:0] count;
-
- always @(posedge clk) begin
- if(rst_n == 0)begin
- end
- else begin
- count ++;
- data <= count;
- if(count == 150)begin
- $finish;
- end
- end
- end
- endmodule
dut_assert.sv :
- module dut_assert(clk_sva, rst_n_sva, vld_sva, rdy_sva, data_sva);//这里全都是 input
- input clk_sva,rst_n_sva,vld_sva;
- input rdy_sva;
- input reg[31:0] data_sva;
-
-
- always @(posedge clk_sva)begin
-
- @(posedge clk_sva);
-
- if(data_sva == 10)begin
- $display("++++canli data_sva is %d at %0t",data_sva, $time);
- end
- if(data_sva == 13)begin
- $display("****canli data_sva is %d at %0t",data_sva, $time);
- end
- end
- endmodule
test.sv :
- module test;
-
- bit clk;
- bit rst_n;
- bit [31:0] data;
- bit rdy;
-
- initial begin
- #10 rst_n = 1;
- forever begin
- #1 clk = ~clk;
- end
-
- end
- initial begin
- $timeformat(-9, 0, "ns", 20);
- $fsdbDumpfile("top.fsdb");
- $fsdbDumpvars(0, test);
- $fsdbDumpflush;
- $fsdbDumpSVA;
- end
-
- dut my_dut(.clk(clk),.rst_n(rst_n),.vld(1'd0),.rdy(rdy),.data(data));
-
- endmodule
然后通过 bind 将 dut 与 dut_assert 连接起来,写在 assert.sv 中:
- bind dut dut_assert my_assert(
- .clk_sva(clk),
- .rst_n_sva(rst_n),
- .vld_sva(vld),
- .rdy_sva(rdy),
- .data_sva(data)
- );
然后filelist 文件如下:
- ./dut.v
- ./dut_assert.sv
- ./assert.sv
- ./test.sv
运行结果如下:

从上面的例子可以看到:即使 dut_assert.sv 中不包含 断言,bind 依旧可以将 dut_assert 与 dut 连接起来;不过一般来说,在 dut_assert 中一般添加断言来检测dut,否则这样的 bind 看上去似乎没啥子意义;
也可以将 bind 语句加到 test.sv 中,运行结果是一样的,如下:
- module test;
-
- bit clk;
- bit rst_n;
- bit [31:0] data1;
- bit [31:0] data2;
- bit rdy1;
- bit rdy2;
-
- initial begin
- #10 rst_n = 1;
- forever begin
- #1 clk = ~clk;
- end
-
- end
- initial begin
- $timeformat(-9, 0, "ns", 20);
- $fsdbDumpfile("top.fsdb");
- $fsdbDumpvars(0, test);
- $fsdbDumpflush;
- $fsdbDumpSVA;
- end
-
- dut my_dut(.clk(clk),.rst_n(rst_n),.vld(1'd0),.rdy(rdy1),.data(data1));
-
- bind dut dut_assert my_assert(//这里的 dut 也可以是 my_dut
- .clk_sva(clk),
- .rst_n_sva(rst_n),
- .vld_sva(vld),
- .rdy_sva(rdy),
- .data_sva(data)
- );
-
- endmodule
此时,如果将 dut 实例化2次,如下:
- module test;
-
- bit cl;//注意这里名字变了
- bit rst_n;
- bit [31:0] data1;
- bit [31:0] data2;
- bit rdy1;
- bit rdy2;
-
- initial begin
- #10 rst_n = 1;
- forever begin
- #1 cl = ~cl;
- end
-
- end
- initial begin
- $timeformat(-9, 0, "ns", 20);
- $fsdbDumpfile("top.fsdb");
- $fsdbDumpvars(0, test);
- $fsdbDumpflush;
- $fsdbDumpSVA;
- end
-
- dut my_dut1(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy1),.data(data1));
- dut my_dut2(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy2),.data(data2));
-
- bind dut dut_assert my_assert(//注意这里 bind 的还是 dut
- .clk_sva(clk), //这里绑定的还是 clk
- .rst_n_sva(rst_n),
- .vld_sva(vld),
- .rdy_sva(rdy),
- .data_sva(data)
- );
-
- endmodule
运行结果如下:

可以看到,此时 bind dut,相当于 bind 了2次,所以打印语句打印2次;如果将上面的 bind dut 修改:
- module test;
-
- bit cl;
- bit rst_n;
- bit [31:0] data1;
- bit [31:0] data2;
- bit rdy1;
- bit rdy2;
-
- initial begin
- #10 rst_n = 1;
- forever begin
- #1 cl = ~cl;
- end
-
- end
- initial begin
- $timeformat(-9, 0, "ns", 20);
- $fsdbDumpfile("top.fsdb");
- $fsdbDumpvars(0, test);
- $fsdbDumpflush;
- $fsdbDumpSVA;
- end
-
- dut my_dut1(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy1),.data(data1));
- dut my_dut2(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy2),.data(data2));
-
- bind my_dut1 dut_assert my_assert(// 这里 bind 的修改为 my_dut1
- .clk_sva(clk),
- .rst_n_sva(rst_n),
- .vld_sva(vld),
- .rdy_sva(rdy),
- .data_sva(data)
- );
-
- endmodule
运行结果如下:

也就是说,此时改为 dut 的实例名,相当于只 bind 了1次,所以打印1次;如果修改 bind 的端口信号名:
- module test;
-
- bit cl;
- bit rst_n;
- bit [31:0] data1;
- bit [31:0] data2;
- bit rdy1;
- bit rdy2;
-
- initial begin
- #10 rst_n = 1;
- forever begin
- #1 cl = ~cl;
- end
-
- end
- initial begin
- $timeformat(-9, 0, "ns", 20);
- $fsdbDumpfile("top.fsdb");
- $fsdbDumpvars(0, test);
- $fsdbDumpflush;
- $fsdbDumpSVA;
- end
-
- dut my_dut1(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy1),.data(data1));
- dut my_dut2(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy2),.data(data2));
-
- bind my_dut1 dut_assert my_assert(
- .clk_sva(cl), //这里 bind 的信号改为 cl
- .rst_n_sva(rst_n),
- .vld_sva(vld),
- .rdy_sva(rdy),
- .data_sva(data)
- );
-
- endmodule
此时运行会报错,如下:

由此,可以得出结论,bind 时,bind 的 dut 中的信号必须是 dut module中的信号名,而不能是 dut 实例的输入输出信号名!!
最近看到一种bind 方式来大批量 bind ,语法如下:
- bind module_name: module_inst_name1, module_inst_name2...
- checker_module[#(.Para(xx))] checker_module_inst
- // checker_module 可以带 parameter
例子如下:
bind DUT: dut_inst1, dut_inst2 checker#(.a(1)) checker_inst(.*);