• systemverilog中的bind


    最早接触 bind 关键字是在assertion 当中,将assertion 与 dut 进行绑定连接,如下例子:

    1. bind cpu fpu_props fpu_rules_1(a,b,c);
    2. //cpu 是module 名字
    3. //fpu_props 是内部包含 property 以及断言的模块,可以是 module 或者 program 甚至 interface
    4. //fpu_rules_1 是 fpu_props 的实例名
    5. //括号中的信号 a b c 是 cpu 的端口信号,并且连接到 fpu_props 的对应端口

    来看下面一个将 interface bind 到 module 的例子:

    1. interface range (input clk,enable, input int minval,expr);
    2. property crange_en;
    3. @(posedge clk) enable |-> (minval <= expr);
    4. endproperty
    5. range_chk: assert property (crange_en);
    6. endinteface
    7. bind cr_unit range r1(c_clk,c_en,v_low,(in1&&in2));

    可以看到,包含断言的 interface ,其端口信号的方向均为 input ,也就是说 property 中包含的信号都是从 interface 的外部给进来的;

    实际上, bind 不仅仅 可以进行 断言 与 dut 之间的连接,两个 module 之间也能进行连接,如下面例子:

    有 dut.v :

    1. module dut(clk, rst_n, vld, rdy, data);
    2. input clk;
    3. input rst_n;
    4. input vld;
    5. output reg rdy;
    6. output reg[31:0] data;
    7. bit[31:0] count;
    8. always @(posedge clk) begin
    9. if(rst_n == 0)begin
    10. end
    11. else begin
    12. count ++;
    13. data <= count;
    14. if(count == 150)begin
    15. $finish;
    16. end
    17. end
    18. end
    19. endmodule

    dut_assert.sv :

    1. module dut_assert(clk_sva, rst_n_sva, vld_sva, rdy_sva, data_sva);//这里全都是 input
    2. input clk_sva,rst_n_sva,vld_sva;
    3. input rdy_sva;
    4. input reg[31:0] data_sva;
    5. always @(posedge clk_sva)begin
    6. @(posedge clk_sva);
    7. if(data_sva == 10)begin
    8. $display("++++canli data_sva is %d at %0t",data_sva, $time);
    9. end
    10. if(data_sva == 13)begin
    11. $display("****canli data_sva is %d at %0t",data_sva, $time);
    12. end
    13. end
    14. endmodule

    test.sv :

    1. module test;
    2. bit clk;
    3. bit rst_n;
    4. bit [31:0] data;
    5. bit rdy;
    6. initial begin
    7. #10 rst_n = 1;
    8. forever begin
    9. #1 clk = ~clk;
    10. end
    11. end
    12. initial begin
    13. $timeformat(-9, 0, "ns", 20);
    14. $fsdbDumpfile("top.fsdb");
    15. $fsdbDumpvars(0, test);
    16. $fsdbDumpflush;
    17. $fsdbDumpSVA;
    18. end
    19. dut my_dut(.clk(clk),.rst_n(rst_n),.vld(1'd0),.rdy(rdy),.data(data));
    20. endmodule

    然后通过 bind 将 dut 与 dut_assert 连接起来,写在 assert.sv 中:

    1. bind dut dut_assert my_assert(
    2. .clk_sva(clk),
    3. .rst_n_sva(rst_n),
    4. .vld_sva(vld),
    5. .rdy_sva(rdy),
    6. .data_sva(data)
    7. );

    然后filelist 文件如下:

    1. ./dut.v
    2. ./dut_assert.sv
    3. ./assert.sv
    4. ./test.sv

    运行结果如下:

     从上面的例子可以看到:即使 dut_assert.sv 中不包含 断言,bind 依旧可以将 dut_assert 与 dut 连接起来;不过一般来说,在 dut_assert 中一般添加断言来检测dut,否则这样的 bind 看上去似乎没啥子意义;

    也可以将 bind 语句加到 test.sv 中,运行结果是一样的,如下:

    1. module test;
    2. bit clk;
    3. bit rst_n;
    4. bit [31:0] data1;
    5. bit [31:0] data2;
    6. bit rdy1;
    7. bit rdy2;
    8. initial begin
    9. #10 rst_n = 1;
    10. forever begin
    11. #1 clk = ~clk;
    12. end
    13. end
    14. initial begin
    15. $timeformat(-9, 0, "ns", 20);
    16. $fsdbDumpfile("top.fsdb");
    17. $fsdbDumpvars(0, test);
    18. $fsdbDumpflush;
    19. $fsdbDumpSVA;
    20. end
    21. dut my_dut(.clk(clk),.rst_n(rst_n),.vld(1'd0),.rdy(rdy1),.data(data1));
    22. bind dut dut_assert my_assert(//这里的 dut 也可以是 my_dut
    23. .clk_sva(clk),
    24. .rst_n_sva(rst_n),
    25. .vld_sva(vld),
    26. .rdy_sva(rdy),
    27. .data_sva(data)
    28. );
    29. endmodule

    此时,如果将 dut 实例化2次,如下:

    1. module test;
    2. bit cl;//注意这里名字变了
    3. bit rst_n;
    4. bit [31:0] data1;
    5. bit [31:0] data2;
    6. bit rdy1;
    7. bit rdy2;
    8. initial begin
    9. #10 rst_n = 1;
    10. forever begin
    11. #1 cl = ~cl;
    12. end
    13. end
    14. initial begin
    15. $timeformat(-9, 0, "ns", 20);
    16. $fsdbDumpfile("top.fsdb");
    17. $fsdbDumpvars(0, test);
    18. $fsdbDumpflush;
    19. $fsdbDumpSVA;
    20. end
    21. dut my_dut1(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy1),.data(data1));
    22. dut my_dut2(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy2),.data(data2));
    23. bind dut dut_assert my_assert(//注意这里 bind 的还是 dut
    24. .clk_sva(clk), //这里绑定的还是 clk
    25. .rst_n_sva(rst_n),
    26. .vld_sva(vld),
    27. .rdy_sva(rdy),
    28. .data_sva(data)
    29. );
    30. endmodule

    运行结果如下:

    可以看到,此时 bind dut,相当于 bind 了2次,所以打印语句打印2次;如果将上面的 bind dut 修改:

    1. module test;
    2. bit cl;
    3. bit rst_n;
    4. bit [31:0] data1;
    5. bit [31:0] data2;
    6. bit rdy1;
    7. bit rdy2;
    8. initial begin
    9. #10 rst_n = 1;
    10. forever begin
    11. #1 cl = ~cl;
    12. end
    13. end
    14. initial begin
    15. $timeformat(-9, 0, "ns", 20);
    16. $fsdbDumpfile("top.fsdb");
    17. $fsdbDumpvars(0, test);
    18. $fsdbDumpflush;
    19. $fsdbDumpSVA;
    20. end
    21. dut my_dut1(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy1),.data(data1));
    22. dut my_dut2(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy2),.data(data2));
    23. bind my_dut1 dut_assert my_assert(// 这里 bind 的修改为 my_dut1
    24. .clk_sva(clk),
    25. .rst_n_sva(rst_n),
    26. .vld_sva(vld),
    27. .rdy_sva(rdy),
    28. .data_sva(data)
    29. );
    30. endmodule

     运行结果如下:

    也就是说,此时改为 dut 的实例名,相当于只 bind 了1次,所以打印1次;如果修改 bind 的端口信号名:

    1. module test;
    2. bit cl;
    3. bit rst_n;
    4. bit [31:0] data1;
    5. bit [31:0] data2;
    6. bit rdy1;
    7. bit rdy2;
    8. initial begin
    9. #10 rst_n = 1;
    10. forever begin
    11. #1 cl = ~cl;
    12. end
    13. end
    14. initial begin
    15. $timeformat(-9, 0, "ns", 20);
    16. $fsdbDumpfile("top.fsdb");
    17. $fsdbDumpvars(0, test);
    18. $fsdbDumpflush;
    19. $fsdbDumpSVA;
    20. end
    21. dut my_dut1(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy1),.data(data1));
    22. dut my_dut2(.clk(cl),.rst_n(rst_n),.vld(1'd0),.rdy(rdy2),.data(data2));
    23. bind my_dut1 dut_assert my_assert(
    24. .clk_sva(cl), //这里 bind 的信号改为 cl
    25. .rst_n_sva(rst_n),
    26. .vld_sva(vld),
    27. .rdy_sva(rdy),
    28. .data_sva(data)
    29. );
    30. endmodule

     此时运行会报错,如下:

     由此,可以得出结论,bind 时,bind 的 dut 中的信号必须是 dut module中的信号名,而不能是 dut 实例的输入输出信号名!!

    最近看到一种bind 方式来大批量 bind ,语法如下:

    1. bind module_name: module_inst_name1, module_inst_name2...
    2. checker_module[#(.Para(xx))] checker_module_inst
    3. // checker_module 可以带 parameter

    例子如下:

    bind DUT: dut_inst1, dut_inst2  checker#(.a(1)) checker_inst(.*);

  • 相关阅读:
    mybatis 数据库字段为空or为空串 忽略条件过滤, 不为空且不为空串时才需nameParam过滤条件
    数据结构——栈和队列
    Rust Wasm 图片转 ASCII 艺术
    【linux】SourceForge 开源软件开发平台和仓库
    OSPF——DR和BDR讲解
    【vue】 vue2 监听滚动条滚动事件
    【ESP32_8266_WiFi (十二)】ESP8266客户端HTTP API应用实例
    【Vue】把页面上的某个div转化成base64图片,并且下载到本地。vue、h5页面下载图片到本地。页面转化base64文件下载到本地
    科普读书会丨《被讨厌的勇气》:愤怒不是目的,是一种工具
    C++11新特性之auto、decltype
  • 原文地址:https://blog.csdn.net/bleauchat/article/details/127116581