• SystemVerilog Randomization点点滴滴


    目录

    0. 前言

    1. RANDOMIZE() VS STD::RANDOMIZE()

    2. ADDING CONSTRAINTS WITH STD::RANDOMIZE() WITH

    3. 随机模式关闭后约束还有效吗?

    4. pre/post_randomize()在子类和父类中的调用顺序是什么?

    5. pre/post_randomize()是虚方法吗?


    0. 前言

            零零碎碎地记载一些关于SystemVerilog随机化的问题,结合代码实验进行解析。以下的代码的运行均利用windows版的QuestaSim。关于基本的仿真命令使用方法可以参考:数字电路设计仿真方法入门

            本笔记随时动态更新。 

    1. RANDOMIZE() VS STD::RANDOMIZE()

            RANDOMIZE()是SV的类内建的随机化函数,STD::RANDOMIZE()是独立的随机化函数。

            每一个类都内建(built-in)虚方法 randomize(), 其声明如下(注意,如下面所述,回调函数pre/post_randomize()不是虚方法!): 

                    virtual function int randomize();         

            randomize()用于对类中定义为rand或者randc类型的成员变量进行随机化处理。但是randomize()不会被自动调用。类中的成员定义为rand或者randc类型后,需要显式调用来产生所有随机变量的随机采样值(遵循约束条件)。关于class::randomize(),有以下几点需要注意:

    • If randomize() fails, then post_randomize() is not called. 关于post_randomize(),请参考后面章节。
    • randomize() method is built-in and cannot be overriden. randomize()不能被override!开发者不能自己去重新定义randomize()
    • If randomization fails, then the variables retain their original values and are not modified。如过随机化失败(比如说,约束条件无法满足),
    1. class trans;
    2. rand bit [3:0] data1;
    3. randc bit [3:0] data2;
    4. bit [7:0] data3;
    5. constraint c_data1 { data1 >= 8;}
    6. constraint c_data2 { data2 < 8;}
    7. function void pre_randomize();
    8. $display("trans: called before randomization!");
    9. endfunction
    10. function void post_randomize();
    11. $display("trans: called after randomization!");
    12. endfunction
    13. endclass
    14. module test1;
    15. initial begin
    16. int var1;
    17. trans tr;
    18. tr = new();
    19. if(tr.randomize())
    20. $display("Randomization successful ! data1 = %0d \t data2 = %0d \t data3 = %0d",tr.data1,tr.data2, tr.data3);
    21. else
    22. $display("Randomization failed ! ");
    23. void'(std::randomize(var1));
    24. $display("var1 = %0d",var1);
    25. void'(std::randomize(tr.data1));
    26. void'(std::randomize(tr.data3));
    27. $display("after std::randomize(): tr.data1 = %0d, tr.data1 = %0d",tr.data1,tr.data3);
    28. end
    29. endmodule

            std::randomize()可以用于对当前作用域中任何变量进行随机化处理,即便该变量并没有被声明为随机化类型。

            std::randomize()也可以用于对类的成员进行随机化处理!不管它是否被定义为rand类型。虽然这个并不在SV标准要求的范围以内。

            运行以上代码会报告以下编译警告:

    # ** Warning: pre_post_randomize.sv(77): (vopt-2961) Argument #1 for std::randomize() function is non-LRM compliant.
    # ** Warning: pre_post_randomize.sv(78): (vopt-2961) Argument #1 for std::randomize() function is non-LRM compliant.

            但是它的确是能够工作的,运行结果如下所示:

     VSIM 1> run -all
    # trans: called before randomization!
    # trans: called after randomization!
    # Randomization successful ! data1 = 14          data2 = 3       data3 = 0
    # var1 = 393546790
    # after std::randomize(): tr.data1 = 6, tr.data1 = 241

    2. ADDING CONSTRAINTS WITH STD::RANDOMIZE() WITH

            不仅是类的内建randomize()可以带约束条件运行,std::randomize()也同样可以。当带约束调用std::randomize()时,randomize()的输入参数变量为待随机化变量,其它的变量则当作状态变量使用。如以下例码所示:

    1. module test5;
    2. int x, y, z, status;
    3. int d_length;
    4. initial begin
    5. d_length = $urandom_range(1,1000);
    6. status = std::randomize( x, y, z ) with { x < y ; x + y < d_length ; };
    7. $display("\tx = %0d \t y = %0d \t z = %0d \t d_length = %0d", x,y,z,d_length);
    8. status = std::randomize( x, y ) with { y - x > d_length ; };
    9. $display("\tx = %0d \t y = %0d \t z = %0d \t d_length = %0d", x,y,z,d_length);
    10. end
    11. endmodule

    VSIM 1> run -all
    #       x = -1763570032          y = 31477632    z = 877272384   d_length = 913
    #       x = -1050698721          y = -438691868          z = 877272384   d_length = 913

    3. 随机模式关闭后约束还有效吗?

            设计一个简单的代码实验如下所示:

    1. //class
    2. class trans;
    3. rand bit [3:0] data1;
    4. randc bit [3:0] data2;
    5. constraint c_data1 { data1 >= 8;}
    6. constraint c_data2 { data2 < 8;}
    7. endclass
    8. module test3;
    9. initial begin
    10. trans tr;
    11. tr = new();
    12. tr.rand_mode(0);
    13. tr.randomize();
    14. $display("\tdata1 = %0d \t data2 = %0d",tr.data1,tr.data2);
    15. for(int i=0; i<8; i++) begin
    16. tr.data1 = i;
    17. tr.data2 = i + 8;
    18. $display("\tdata1 = %0d \t data2 = %0d",tr.data1,tr.data2);
    19. end
    20. end
    21. endmodule

            编译运行以上test3,可以得到结果如下:

    #       data1 = 0        data2 = 0
    #       data1 = 0        data2 = 8
    #       data1 = 1        data2 = 9
    #       data1 = 2        data2 = 10
    #       data1 = 3        data2 = 11
    #       data1 = 4        data2 = 12
    #       data1 = 5        data2 = 13
    #       data1 = 6        data2 = 14
    #       data1 = 7        data2 = 15

            由于随机化模式关闭了, 虽然对data1和data2的显式赋值全部违反约束但是并没有引发报错。同样,由于随机化模式关闭了,data1和data2被初始化为0了。

    4. pre/post_randomize()在子类和父类中的调用顺序是什么?

            这个问题其实有点坑。基于以下实验代码来进行说明。child_trans1/2/3都继承于child_trans,在child_trans中定义了pre/post_randomize()。

            child_trans1中显式定义了pre/post_randomize(),但是其中没有显式调用super.pre/post_randomize()。child_trans2中显式定义了pre/post_randomize(),但是其中显式调用super.pre/post_randomize()。child_trans3中没有显式定义了pre/post_randomize()。        

    1. //class
    2. class trans;
    3. rand bit [3:0] data1;
    4. randc bit [3:0] data2;
    5. constraint c_data1 { data1 >= 8;}
    6. constraint c_data2 { data2 < 8;}
    7. function void pre_randomize();
    8. $display("trans: called before randomization!");
    9. endfunction
    10. function void post_randomize();
    11. $display("trans: called after randomization!");
    12. endfunction
    13. endclass
    14. class child_trans1 extends trans;
    15. rand bit [3:0] data3;
    16. randc bit [3:0] data4;
    17. constraint c_data3 { data3 >= 8;}
    18. constraint c_data4 { data4 < 8;}
    19. function void pre_randomize();
    20. $display("child_trans1: called before randomization!");
    21. endfunction
    22. function void post_randomize();
    23. $display("child_trans1: called after randomization!");
    24. endfunction
    25. endclass
    26. class child_trans2 extends trans;
    27. rand bit [3:0] data5;
    28. randc bit [3:0] data6;
    29. constraint c_data5 { data5 >= 8;}
    30. constraint c_data6 { data6 < 8;}
    31. function void pre_randomize();
    32. super.pre_randomize();
    33. $display("child_trans2: called before randomization!");
    34. endfunction
    35. function void post_randomize();
    36. super.post_randomize();
    37. $display("child_trans2: called after randomization!");
    38. endfunction
    39. endclass
    40. class child_trans3 extends trans;
    41. rand bit [3:0] data7;
    42. randc bit [3:0] data8;
    43. constraint c_data7 { data7 >= 8;}
    44. constraint c_data8 { data8 < 8;}
    45. endclass
    46. module test1;
    47. initial begin
    48. trans tr;
    49. tr = new();
    50. if(tr.randomize())
    51. $display("Randomization successful ! data1 = %0d \t data2 = %0d",tr.data1,tr.data2);
    52. else
    53. $display("Randomization failed ! ");
    54. end
    55. endmodule
    56. module test2;
    57. initial begin
    58. child_trans1 ctr;
    59. ctr = new();
    60. void'(ctr.randomize());
    61. $display("\tdata1 = %0d \t data2 = %0d \t data3 = %0d \t data4 = %0d",
    62. ctr.data1,ctr.data2,ctr.data3,ctr.data4);
    63. end
    64. endmodule
    65. module test3;
    66. initial begin
    67. child_trans2 ctr;
    68. ctr = new();
    69. void'(ctr.randomize());
    70. $display("\tdata1 = %0d \t data2 = %0d \t data5 = %0d \t data5 = %0d",
    71. ctr.data1,ctr.data2,ctr.data5,ctr.data5);
    72. end
    73. endmodule
    74. module test4;
    75. initial begin
    76. child_trans3 ctr;
    77. ctr = new();
    78. void'(ctr.randomize());
    79. $display("\tdata1 = %0d \t data2 = %0d \t data7 = %0d \t data8 = %0d",
    80. ctr.data1,ctr.data2,ctr.data7,ctr.data8);
    81. end
    82. endmodule

            编译以下代码文件并分别运行work.test2,work.test3,work.test4.

    work.test2:

    # child_trans1: called before randomization!
    # child_trans1: called after randomization!

    work.test3: 

    # trans: called before randomization!
    # child_trans2: called before randomization!
    # trans: called after randomization!
    # child_trans2: called after randomization!

     work.test4: 

    # trans: called before randomization!
    # trans: called after randomization!

            基于以上实验可以看出,pre/post_randomize()在类的继承中的调用行为与普通的systemverilog的类的方法的行为是一致的,即:

    • (1) 同名同参数时,子类方法覆盖父类方法,父类方法不会被调用
    • (2) 同名同参数时,如果希望父类方法得到调用,需要在子类方法中以super.methodname()的形式对父类方法进行显式调用
    • (3) 如果子类没有定义的话,缺省地会调用父类的方法

    5. pre/post_randomize()是虚方法吗?

            答案是:它们不是虚方法(virtual method),但是它们以虚方法的方式工作(behave as virtual methods)。如果用户自定义类中,将pre/post_randomize()定义为virtual method的话,编译器会报错。比如说,定义类如下的话:

    1. class trans;
    2. rand bit [3:0] data1;
    3. randc bit [3:0] data2;
    4. constraint c_data1 { data1 >= 8;}
    5. constraint c_data2 { data2 < 8;}
    6. virtual function void pre_randomize();
    7. $display("trans: called before randomization!");
    8. endfunction
    9. virtual function void post_randomize();
    10. $display("trans: called after randomization!");
    11. endfunction
    12. endclass

            用questasim编译命令vlog编译后报告如下错误: 

    ** Error: pre_post_randomize.sv(13): (vlog-2943) Invalid use of 'virtual' keyword for built-in function 'post_randomize'
    .
    ** Error: pre_post_randomize.sv(9): (vlog-2943) Invalid use of 'virtual' keyword for built-in function 'pre_randomize'. 

  • 相关阅读:
    Anaconda、Conda、pip、Virtualenv的区别
    计算机毕业设计springboot+vue基本微信小程序的校园二手物品交易平台系统
    CMake个人理解和使用
    mysql导出表结构到excel
    第九章-线程
    Unity接入SQLite (三):C#封装SQL命令
    设计模式:访问者模式
    C++ 异常处理学习笔记
    山区自建房BCD浪涌保护器接线方案(自建房用电防雷)
    语法基础(数组)
  • 原文地址:https://blog.csdn.net/chenxy_bwave/article/details/126123957