• systemverilog学习 ---随机化(2)


    Constraint inside

    前面的约束,采用条件表达式>,倘若随机值是有限个值,并且没有明显的规律,总结表达式会较为困难。sv可以使用inside操作符,表示随机变量会从inside块中取值.
    inside块里面可以是变量,常数和范围。inside之后用大括号,把取值放于括号内。其声明形式如下:

    constraint addr_range {addr inside {...};}
    
    • 1

    对于范围表示要使用[],其声明形式如下:

    constraint addr_range {addr inside {[5:10]};}
    
    • 1

    若是一系列的值,通过逗号分隔。

    constraint addr_range {addr inside {1,3,5,7,9};}
    
    • 1

    对于上述的可以混合使用。

    constraint addr_range {addr inside {1,3,[5:10],12.[13:15]};}
    
    • 1

    吐过想要排除一些值,可以使用!(感叹号),对整个约束取反。

    constraint addr_range {addr !(inside{[5:10]});11}
    
    • 1

    一些随机变量也可以被使用在inside语句块中,如下所示:

    rand bit [3:0]	start_addr	;
    rand bit [3:0]	end_addr	;
    rand bit [3:0]	addr		;
    constraint addr_range {addr inside {[start_addr : end_addr]};}
    
    • 1
    • 2
    • 3
    • 4

    下面给出一个例子:

    class packet;
        rand bit    [3:0]   addr        ;
        rand bit    [3:0]   start_addr  ;
        rand bit    [3:0]   end_addr    ;
    
        constraint addr_1_range {addr inside {[start_addr : end_addr]};}
    endclass
    
    module constr_inside;
        initial begin
            packet pkt;
            pkt = new();
            $display("----------------------------------------------");
            repeat(3) begin
                pkt.randomize();
                $display("start_addr = %0d, end_addr = %0d", pkt.start_addr, pkt.end_addr);
                $display("\t addr = %0d", pkt.addr);
                $display("----------------------------------------------");
            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

    由下面输出结果看出,addr都是在开始地址和结束地址之间。输出结果如下:

    在这里插入图片描述

    dist constraint

    我们还可能需要控制随机值的概率分布,sv提供dist操作符,可以实现带权重分布,dist需要紧跟一系列的值和权重。其声明形式如下:

    value := weight    or
    value :/ weight
    
    • 1
    • 2

    其中value表示把希望的值赋给一个随机变量,权重表示在随机化过程中这个数值所被考虑的频次。需要注意的是:

    • 数值和权重可以是常数或者是变量
    • 数值可以是一个值,或者一个范围
    • 一个数值的默认权重是1
    • 权重和即所有的weight的和加起来不一定是100,可以自由发挥,并不影响总的概率是1.

    在这里插入图片描述
    value:/weight表示对于值value赋予权重weight,但是如果value是一个范围是,范围内的值会平分权重weight,下面的李忠,10-12共三个取值,因此每个取值概率是8/3.
    在这里插入图片描述

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

    其输出结果是:
    在这里插入图片描述
    理应是10的输出个数最多的,输出最少的个数是2。

    class packet;
    
        rand bit [3:0]  addr_1  ;
        rand bit [3:0]  addr_2  ;
    
        constraint addr_1_range{addr_1 dist {2 := 5, [10:12] := 8};}
        constraint addr_2_range{addr_2 dist {2 :/ 5, [10:12] :/ 8};}
    
    endclass
    
    module constr_dist;
    
        initial begin
            packet pkt;
            pkt = new();
    
            $display("-------------------------------------------");
            repeat(10) begin
                pkt.randomize();
                $display("\t addr_1 = %0d", pkt.addr_1);
            end
            $display("-------------------------------------------");
            $display("-------------------------------------------");
            repeat(10)begin
                pkt.randomize();
                $display("\t addr_2 = %0d", pkt.addr_2);
            end
            $display("-------------------------------------------");
        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

    这里需要理解的是,对于addr_1中,2的权重5,10,11,12对应的权重都是8.而在addr_2中,2的权重是5,而10,11,12的权重都是3/8。因此其输出结果是:
    在这里插入图片描述

    implication constraints

    implication是隐含的意思,systemverilog提供隐含操作符(->)。可以用来声明两个变量之间的关系。一般被放置于表达式和约束条件之间。即:

    expression -> contraint
    
    • 1

    只有当左面的表达式为真的时候,右边的约束才会被考虑。

    class packet;
    
        rand bit [3:0]      addr        ;
        string              addr_range  ;
    
        constraint address_range {(addr_range == "small") -> (addr < 8);}
    endclass
    
    module constr_implication;
    
        initial begin
            packet pkt;
            pkt = new();
    
            pkt.addr_range = "small";
            $display("---------------------------------------------");
            repeat(4) begin
                pkt.randomize();
                $display("\t addr_range = %s addr = %0d", pkt.addr_range, pkt.addr);
            end
            $display("---------------------------------------------");
        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

    如上面例子,若addr_range等于small的话,那么才会有约束的随机化,如若不是small的话,则约束将不会生效。输出结果是:
    在这里插入图片描述

    if else 的约束

    if else的语句块中也允许约束的条件执行,如果这个表达式是真,那么在一个约束块中所有的约束都会被满足,否则是在else的语句块中的约束会被满足。

    class packet;
    
        rand bit [3:0]  addr        ;
        string          addr_range  ;
    
        constraint address_range {
            if(addr_range == "small")
                addr < 8;
            else
                addr > 8;
        }
    
    endclass
    
    module constr_if_else;
    
        initial begin
            packet pkt;
            pkt = new();
            pkt.addr_range = "small";
            $display("----------------------------------------------------");
            repeat(3) begin
                pkt.randomize();
                $display("\t addr_range = %s addr = %0d", pkt.addr_range, pkt.addr);
            end
            $display("----------------------------------------------------");
            pkt.addr_range = "high";
            $display("----------------------------------------------------");
            repeat(3)begin
                pkt.randomize();
                $display("\t addr_range = %s addr = %0d", pkt.addr_range, pkt.addr);
            end
            $display("----------------------------------------------------");
        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
    • 32
    • 33
    • 34
    • 35
    • 36

    上面例子中,若addr_range是small,则随机化后的addr值都会小于8,如果是high的话,那么随机化后的addr值都会大于8.因此其输出结果如下所示:
    在这里插入图片描述

    foreach constraint

    在systemverilog中的contraint块中也支持foreach循环。使用foreach对于数据的约束将是非常简单的。因此也叫做循环约束。在约束数组时,我们要指定或者约束动态数组的大小。其约束形式如下所示:

    constraint constraint_name { foreach ( variable[iterator] )  variable[iterator] <..conditions..>  }
    
    • 1

    下面的例子:

    class packet;
    
        rand byte addr [];
        rand byte data [];
        
        constraint avalues {
            foreach(addr[i])
                addr[i] inside {4, 8, 12, 16};
        }
    
        constraint dvalues {
            foreach(data[j])
                data[j] > 4 * j;
        }
    
        constraint asize {addr.size < 4;}
        constraint dsize {data.size == addr.size;}
    endclass
    
    module constr_iteration;
    
        initial begin
            packet pkt;
            pkt = new();
    
            $display("--------------------------------------------");
            repeat(3) begin
                pkt.randomize();
                $display("\t addr-size = %0d data-size = %0d", pkt.addr.size(), pkt.data.size());
                foreach(pkt.addr[i])
                    $display("\t addr = %0d data = %0d", pkt.addr[i], pkt.data[i]);
                    $display("--------------------------------------------");
            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
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    显示addr 动态数组的元素必须时4,8,12,16,且大小必须小于4,而data数组的元素必须大于它的Index的4倍。约束两个动态数组的大小相等。其输出结果如下所示,当数组的大小为0时,则没有元素输出。
    在这里插入图片描述

    disable constraint

    使用constraint_mode方法不使能一个类中的约束。默认情况下所有约束都会被使能。类似我们前文所提出的rand_mode方法。constraint_mode方法可以用来不使能任何特定的约束块。

    • constraint_mode(1)表示约束被使能
    • constraint_mode(0)表示约束被不使能
    • 返回约束块的状态
      其声明形式如下:
    <object_hanlde>.<constraint_block_name>.constraint_mode(enable);
    //enable == 1, constraint block enable
    //enable == 0, constraint block disable
    
    • 1
    • 2
    • 3

    下面这个例子没有不使能约束条件,因此会随机选取5或者10中一个数进行打印输出,代码如下所示:
    在这里插入图片描述
    其输出结果是:
    在这里插入图片描述
    但是若在上面例子中加上不使能约束,则:
    在这里插入图片描述
    其输出结果是:
    在这里插入图片描述
    其实contraint_mode()可以返回约束块的状态:

    class packet;
    
        rand bit [3:0]  addr;
        constraint addr_range {addr inside {5, 10 , 14};}
    
    endclass
    
    module static_constr;
    
        initial begin
            packet pkt;
            pkt = new();
    
            $display("Before Constraint disable");
            $display("Value of constraint mode = %0d", pkt.addr_range.constraint_mode());
            pkt.randomize();
            $display("\t addr = %0d", pkt.addr);
    
            //disabling constraint
            pkt.addr_range.constraint_mode(0);
    
            $display("After Constraint disable");
            $display("Value of constraint mode = %0d", pkt.addr_range.constraint_mode());
            pkt.randomize();
            $display("\t addr = %0d", pkt.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

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

  • 相关阅读:
    数据库: 存储过程
    Vue封神之路(2.) Vue简介
    表单校验wed第十九章
    @Transactional & @Aysnc & 循环依赖 & 事务同步问题
    吴恩达《机器学习》9-1-9-3:反向传播算法、反向传播算法的直观理解
    如何提高webpack的构建速度?
    【Linux】内存屏障
    c++入门
    一句话总结设计模式
    Empowering Long-tail Item Recommendation through Cross Decoupling Network (CDN)
  • 原文地址:https://blog.csdn.net/weixin_45614076/article/details/126328563