• systemverilog学习 === 随机化约束(完结)


    static constraint

    在systemverilog中,静态的约束和静态的类的性质类似。一个约束块可以被定义为静态的,通过在它的定义中添加static关键字,此时这个约束块叫做静态约束,所有类的实例共享这个静态约束块。因此该类的任一句柄改变constraint_mode将会影响其他实例。约束形式为:

    static constraint constraint_name { ....; }
    
    • 1

    以下是一个例子:

    class packet;
    
        rand bit [7:0]  addr    ;
    
        static constraint addr_range {addr == 5;}
    
    endclass
    
    module static_constr;
    
        initial begin
            packet pkt1;
            packet pkt2;
            pkt1 = new();
            pkt2 = new();
    
            $display("Before disabling constraint");
            pkt1.randomize();
            $display("\t pkt1.addr = %0d", pkt1.addr);
            pkt2.randomize();
            $display("\t pkt2.addr = %0d", pkt2.addr);
    
            pkt2.addr_range.constraint_mode(0);
    
            $display("After disabling constraint");
            pkt1.randomize();
            $display("\t pkt1.addr = %0d", pkt1.addr);
            pkt2.randomize();
            $display("\t pkt2.addr = %0d", pkt2.addr);
        end
    endmodule
    
    • 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

    结果如下,可见尽管是pkt2调用了constraint_mode方法,句柄pkt1指向的实例也受影响。
    在这里插入图片描述

    inline constraint

    约束是写在类的里面的,内联约束允许使用者对类内的约束增加额外的约束,内联约束写在类的外面,同时还有randomize方。
    使用关键字with,约束求解器constraint solver会同时考虑内联约束和类内约束。内联约束不会覆盖override类内约束,并且不能和类内约束冲突,否则将导致随机化失败。其使用方法如下:

    object.randomize()with{...};
    
    • 1
    class packet;
    
        rand bit [3:0]  addr;
    
    endclass
    
    module inline_constr;
    
        initial begin
            packet pkt;
            pkt = new();
    
            repeat(2) begin
                pkt.randomize()with{addr == 8;};
                $display("\taddr = %0d", pkt.addr);
            end
        end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    如上面这个例子,在类内并没有约束,在类外添加约束,addr = 8,结果输出如下所示:
    在这里插入图片描述

    class packet;
    
        rand bit [3:0]  addr;
        rand bit [3:0]  data;
    
        constraint data_range{data > 0; data < 10;}
    
    endclass
    
    module inline_constr;
    
        initial begin
            packet pkt;
            pkt = new();
            repeat(2)begin
                pkt.randomize()with {addr == 8;};
                $display("\t addr = %0d data = %0d", pkt.addr, pkt.data);
            end
        end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    上面这个在类内和类外都有约束,其输出结果为:
    在这里插入图片描述
    如果再加个约束data = 12,那么编译器就会报错:
    在这里插入图片描述
    报错的信息如下:
    在这里插入图片描述

    function in constraint

    在一些情况下,不能在一个整行写完约束。因此我们可以使用function来约束随机变量,约束逻辑要写在function的内部。

    • function要卸载约束块外
    • 约束逻辑要卸载函数的内部,函数的定义和函数的调用要写在约束块内。此外,function要在求解约束前调用,他们的返回值视为状态变量state.

    使用方法为:

    constraint constraint_name { var = function_call(); };
    
    • 1
    class packet;
    
        rand bit [3:0]  start_addr;
        rand bit [3:0]  end_addr;
    
        constraint start_addr_c {
            start_addr == s_addr(end_addr);
        }
    
        function bit [3:0]  s_addr(bit [3:0] e_addr);
            if(e_addr < 4)
                s_addr = 0;
            else
                s_addr = e_addr - 4;
        endfunction
    
    endclass
    
    module func_constr;
    
        initial begin
            packet pkt;
            pkt = new();
            repeat(3) begin
                pkt.randomize();
                $display("\t start_addr = %0d end_addr = %0d", pkt.start_addr, pkt.end_addr);
            end
        end
    endmodule
    
    • 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

    其输出结果为:
    在这里插入图片描述

    软约束

    在systemVerilog中,一个约束被关键字soft约束时,就叫做软约束。通过前文我们可以知道当类的约束和内联约束之间有冲突,那么导致随机化约束失败。但是在一些场景下,我们可能需要覆盖约束,soft就派上用场,soft可以被覆盖。
    考虑如下场景,在testbench中,transaction类的约束用于产生正常的激励,对于错误激励,出错的testcase需要有一个内联约束,该约束有可能会和类内约束冲突。此时,我们只能改变类内的约束,但改动类内约束,会影响到其他testcase。如果可以覆盖类内约束,就迎刃而解了(注,错误激励,会不按正常激励的逻辑产生值,少不了约束冲突)

    class packet;
    
        rand bit [3:0]  addr;
        constraint addr_range {soft addr > 6;}
    endclass
    
    module soft_constr;
    
        initial begin
            packet pkt;
            pkt = new();
    
            repeat(2)begin
                pkt.randomize()with {addr < 6;};
                $display("\t addr = %0d", pkt.addr);
            end
        end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    如上面例子所示,在类中使用软约束addr > 6 ,但是在类外语句中约束其<6.由运行结果所示,约束求解器工作正常,并使用覆盖后的约束条件。输出结果如下所示:

    unique constraint

    约束还可以用unique 修饰,通过unique我们可以给多个变量或者数组元素随机化独一无二的值

    class unique_elements;
    
        rand bit [3:0]  var_1, var_2, var_3;
        rand bit [7:0]  array[6];
        constraint varis_c{unique {var_1, var_2, var_3};}
        constraint array_c{unique {array};}
    
        function void display();
            $display("var_1 = %p", var_1);
            $display("var_2 = %p", var_2);
            $display("var_3 = %p", var_3);
            $display("array = %p", array);
        endfunction
    endclass
    
    program unique_elements_randomization;
    
        unique_elements pkt;
    
        initial begin
            pkt = new();
            pkt.randomize();
            pkt.display();
        end
    
    endprogram
    
    • 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

    其输出结果如下所示,我们可以看出unique保证了其约束的值不会出现重复。

    # var_1 = 10
    # var_2 = 1
    # var_3 = 2
    # array = '{17, 129, 93, 14, 70, 236}
    
    • 1
    • 2
    • 3
    • 4

    bidirectional constraints

    systemverilog中的约束是双向求解的,这意味着对所有的随机变量的约束时并行求解的。在下面的例子中,直观上理解是b依赖于a。但是求解器会认为a依赖于b,b也依赖于a。假设b的内联约束为1,那么为了满足该条件,a就必须为0.

    constraint c_name { if(a == 0) b == 1;
                        else       b == 0; }
    
    • 1
    • 2

    正是如此,sv的约束被成为双向约束。下面的示例,面对三个约束,求解器要同时满足

    class packet;
      rand bit [3:0] a;
      rand bit [3:0] b;
      rand bit [3:0] c;
     
      constraint a_value { a == b + c; }
      constraint b_value { b > 6; }
      constraint c_value { c < 8; }
    endclass
     
    module bidirectional_constr;
      initial begin
        packet pkt;
        pkt = new();
        repeat(5) begin
          pkt.randomize();
          $display("Value of a = %0d \tb = %0d \tc =%0d",pkt.a,pkt.b,pkt.c);
        end
      end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    其输出结果为:

    # Value of a = 3 	b = 15 	c =4
    # Value of a = 2 	b = 13 	c =5
    # Value of a = 15 	b = 15 	c =0
    # Value of a = 13 	b = 11 	c =2
    # Value of a = 0 	b = 11 	c =5
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行结果,要注意a,b,c都是4bit,进位会丢弃,15+4=19=5’h13,截取第四位为3
    在这里插入图片描述
    如上面这个例子中,在module内部通过内联约束b1,为了满足这个条件,就要把a0,而a == 0 就和a =1相互矛盾。编译器会报错:
    在这里插入图片描述

    solve before constraint

    由于求解的双向性,会让一些独立的随机变量影响其他随机变量。要解决此困境,我们可以指定求解顺序
    下例中,通过->,如果a=1,b==0约束生效,a=0时,对b应该没有约束,但b不能为0,为0会使得a要为1。a和b本应该互不影响,但约束的双向性导致a和b互相依赖
    在这里插入图片描述由下面结果可以看出,a = 1出现的概率是很低的。这主要是因为b的取值只有0,a 才可能为1.

    # 	Value of a = 0, b = 12
    # 	Value of a = 0, b = 5
    # 	Value of a = 0, b = 2
    # 	Value of a = 0, b = 1
    # 	Value of a = 0, b = 5
    # 	Value of a = 1, b = 0
    # 	Value of a = 0, b = 9
    # 	Value of a = 0, b = 10
    # 	Value of a = 1, b = 0
    # 	Value of a = 0, b = 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    为了让a=1出现的概率增大,我们应该先求解a,这是因为先求解a并没有约束,这样从概率的角度上来说,a == 1的概率可以提升到50%。我们只用添加下图中红框中的语句就可以了。
    在这里插入图片描述
    运行结果:

    # 	Value of a = 1, b = 0
    # 	Value of a = 0, b = 9
    # 	Value of a = 0, b = 14
    # 	Value of a = 1, b = 0
    # 	Value of a = 0, b = 2
    # 	Value of a = 0, b = 14
    # 	Value of a = 0, b = 9
    # 	Value of a = 1, b = 0
    # 	Value of a = 0, b = 7
    # 	Value of a = 0, b = 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    random系统函数

    $urandom系统函数返回的是一个新的32位的无符号的随机数,varible = $urandom(seed) ,seed是一个可选的参数,决定了产生随机数的顺序,种子可以是一个整数表达式。对一个特定的种子,将会产生相同的值。

    $ random函数的功能和$urandom函数类似,只不过它返回的是一个32位的有符号数。

    $urandom_range函数用作返回在一个范围内的无符号的32位的整数。声明形式如下:

    $urandom_range( int unsigned maxval, int unsigned minval = 0 );addr1 = $urandom_range(30,20);
    addr2 = $urandom_range(20);    //takes max value as '0'
    addr3 = $urandom_range(20,30); //considers max value as '30' and min value as '20'
    
    • 1
    • 2
    • 3

    其函数原型位:

    function int unsigned $urandom_range(int unsigned maxval, int unsigned minval = 0)
    
    • 1

    如果第一个参数比第二个参数小,两个参数的值会被自动调换。
    下面是一个例子:

    module system_funcations;
      bit [31:0] addr1;
      bit [31:0] addr2;
      bit [64:0] addr3;
      bit [31:0] data;
      initial begin
        addr1 = $urandom();
        addr2 = $urandom(89);
        addr3 = {$urandom(),$urandom()};
        data  = $urandom * 6;
     
        $display("addr1=%0d, addr2=%0d, addr3=%0d, data=%0d",addr1,addr2,addr3,data);
      
        addr1 = $urandom_range(30,20);
        addr2 = $urandom_range(20); //takes max value as '0'
        addr3 = $urandom_range(20,30); //considers max value as '30' and min value as '20'
        $display("addr1=%0d, addr2=%0d, addr3=%0d",addr1,addr2,addr3);
      end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    结果:

    # addr1=3948585912, addr2=1979238544, addr3=16107885100594265732, data=4138940696
    # addr1=20, addr2=2, addr3=30
    
    • 1
    • 2
  • 相关阅读:
    【S1002基于vue+nodejs的学生竞赛报名管理系统-哔哩哔哩】 https://b23.tv/xhyyT9U
    建筑模板常见的问题有哪些?
    一篇文章教会你如何编写一个简单的Shell脚本
    modbus通信协议
    嵌入式软件开发新趋势:DevOps
    开箱即用的工具函数库xijs更新指南(v1.2.6)
    【财经研究】并购重组的“不可能三角”
    JAVA计算机毕业设计毕业生论文管理系统Mybatis+源码+数据库+lw文档+系统+调试部署
    [附源码]计算机毕业设计springboot汽车租赁管理系统
    【视觉检测】电源线圈上的导线弯直与否视觉检测系统软硬件方案
  • 原文地址:https://blog.csdn.net/weixin_45614076/article/details/126340602