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


    systemverilog中的随机化

    随机化指的是使得某些事情随机的过程。在systemverulog中的随机化指的是给变量赋值一个随机的值。在verilog中,有$random的方法来产生随机的int数值。但是这仅仅适用于变量,很难适用于类对象的实例的随机化。因此systemverilog引入关键字rand声明随机化,randomize()方法用于产生随机数值。数据随机化能够避免设计人员的主观想法,提高验证的客观性,增加可信度。
    为了声明一个变量是一个随机化的变量,需要使用rand关键字或者randc.以下类型的数据可以被声明为rand或者randc:

    • 整型变量
    • 数组
    • 数组大小
    • 对象的句柄

    对于rand修饰的变量,其值出现概率呈现均匀分布,如rand bit [3:0] addr,addr变量共16种取值,出现0-15的概率都是1/16。而randc,即random-cyclic,它要求所有可能出现的取值都赋值过,才会重复赋以前赋过的值。即randc bit a,变量a假设首先随机化为0,那么下一次一定是1,不能在没赋1前重复赋值0.当然,我们通过rand和randc只是做了声明,要随机化变量,还需要调用randomize方法,即"类句柄.randomize();"

    // class
    class packet;
        rand bit [2:0]  addr1;
        randc bit [2:0] addr2;
    endclass
    
    module rand_methods;
        initial begin
            packet pkt;
            pkt = new();
            repeat(10)begin
                pkt.randomize();
                $display("\t addr1 = %0d \t addr2 = %0d", pkt.addr1, pkt.addr2);
            end
        end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    执行结果如下,randc的随机值会遍历一遍所有的取值,再来一轮新的遍历。要注意的是,使用句柄来调用randomize方法,该方法会对类中所有的随机化变量赋值。
    在这里插入图片描述

    disable randomization

    对于不让随机化变量随机化的要求,systemverilog中是支持的,通过使用随机化的方法rand_mode来disable掉一个变量的随机化。
    rand_mode是disable用rand/randc关键字声明的随机变量。rand_mode可以称为systemverilog的方法,一个变量的使能与否可以通过调用“变量名.rand_mode()”方法,即此时可以用变量命调用,而非类句柄。当随机化使能时,rand_mode方法返回1,否则返回0。

    • rand_mode(1)意味着随机化被开启
    • rand_mode(0)意味着随机化北关掉
    • rand_mode中默认的值是1

    声明形式为:

    <object_hanlde>.<variable_name>.rand_mode(enable);
    //enable = 1, randomization enable
    //enable = 0, randomization disable
    
    • 1
    • 2
    • 3

    在下面这个没有把变量的随机化给关掉,因此变量会得到随机值。

    class packet;
        rand byte addr;
        rand byte data;
    endclass
    
    module rand_methods;
        initial begin
            packet pkt;
            pkt = new();
    
            //calling random method
            pkt.randomize();
    
            $display("\t addr = %0d \t data = %0d", pkt.addr, pkt.data);
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    其输出结果是:
    在这里插入图片描述
    但是若把addr的随机化disable掉。
    在这里插入图片描述
    输出结果就是:
    在这里插入图片描述
    如果想让类中所有变量都不使能随机化,一个一个太麻烦了,我们可以直接"句柄.rand_mode(0)",就能一次性不使能所有变量。

    Randomiztion Methods

    我们的randomize方法,随机化成功会返回1,否则返回0。该方法还会配合pre_randomize和post_randoize回调函数callback。调用randomize方法前会调用pre_randomize方法,调用完randomize 方法后会调用post_randomize方法。程序设计者可以覆pre_randomize和post_randomize方法,即改写以适合自己的需求,如通过pre_randmize使能或不使能随机化,通过post_randomize打印随机化后的值。

    class packet;
        rand bit [7:0]  addr;
        rand bit [7:0]  data;
    
        //pre randomization function
        function void pre_randomize();
            $display("Inside pre_randomize");
        endfunction
    
        //post randomization function
        function void post_randomize();
            $display("Inside post_randomize");
            $display("Value of addr = %0d data = %0d", addr, data);
        endfunction
    endclass
    
    module rand_methods;
        initial begin
            packet pkt;
            pkt = new();
            pkt.randomize();
        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

    例中,randomize以类为基本单位,在类中定义回调函数,然后调用randomize方法就会自动调用pre_randomize和post_randomize方法
    其输出结果是:
    在这里插入图片描述

    //class
    class packet;
        rand bit [31:0]     addr        ;
        randc bit           wr_rd       ;
        bit                 tmp_wr_rd   ;
    
        //pre randomization function - disabling randomization of addr
        //if the prevoious operation is write
        function void pre_randomize();
            if(tmp_wr_rd == 1)
                addr.rand_mode(0);
            else
                addr.rand_mode(1);
        endfunction
    
        //post randomization function - store the wr_rd value to tmp_wr_rd
        //and display randomized values of addr and wr_rd
        function void post_randomize();
            tmp_wr_rd = wr_rd;
            $display("POST_RANDOMIZATION:: Addr = %0h, wr_rd = %0h", addr, wr_rd);
        endfunction
    endclass
    
    module rand_methods;
        initial begin
            packet pkt;
            pkt = new();
            repeat(4) begin
                pkt.randomize();
            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

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

    有约束的随机化(Constrained)

    前面提到,rand类型随机值出现的概率是均匀分布的,我们会有需求如排除一个或多个值,改变概率分布等。sv允许我们写约束,用于控制随机值。
    约束块:

    • 由类的成员组成,比如任务、函数和变量
    • 在一个类中,约束块都有自己独一无二的名字
    • 约束块中包括条件或者表达式来约束或者控制一个随机变量的值
    • 约束块使用大括号{}
    • 约束块可以被定义在类内,也可以被定义在类外作为外部方法。

    声明的形式如下:

    constraint <constraint_block_name> { <condition/expression>; 
                                                  ...
                                        <condition/expression>; }
    
    • 1
    • 2
    • 3
    class packet;
    
        rand bit [3:0]  addr;
    
        constraint add_range {addr > 5;}
    
    endclass
    
    module constr_blocks;
        initial begin
            packet pkt;
            pkt = new();
            repeat(10) begin
                pkt.randomize();
                $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

    在上面的例子中将addr的约束设置为大于5,可以从下图看出所有的输出结果都是大于5的。
    在这里插入图片描述
    要在类外写约束块,需要用类名和作用域解析操作符,并在类中给出约束块名字。
    在这里插入图片描述
    值得注意的是,约束块也是可以继承的,如果子类有同名的约束块,还可以覆盖父类的约束块。下例中,父类packet1的addr需要大于5,而子类的addr则小于5。

    class packet;
      rand  bit [3:0] addr;
      constraint addr_range { addr > 5; }
    endclass
     
    class packet2 extends packet;
      constraint addr_range { addr < 5; } //overriding constraint of parent class
    endclass
     
    module const_inhe;
      initial begin
        packet pkt1;
        packet2 pkt2;
     
        pkt1 = new();
        pkt2 = new();
     
        $display("------------------------------------");
        repeat(5) begin
          pkt1.randomize();
          $display("\tpkt1:: addr = %0d",pkt1.addr);
        end
     
        $display("------------------------------------");
        repeat(5) begin
          pkt2.randomize();
          $display("\tpkt2:: addr = %0d",pkt2.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

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

  • 相关阅读:
    Nginx配置项调优
    【Golang星辰图】Go语言之光照耀数据科学:揭开强大库的神秘面纱
    计算机毕业设计Java餐饮掌上设备点餐系统(源码+系统+mysql数据库+lw文档)
    一篇解决JavaScript
    deepstream--nvinfer
    Gitlab-内嵌数据库迁移到外部postgresql实例
    全新升级!《云原生架构白皮书 2022 版》重磅发布
    HTML+CSS美食静态网页设计——简单牛排美食餐饮(9个页面)公司网站模板企业网站实现
    Swagger的界面太丑,试试knife4j的接口文档吧
    自动补全、
  • 原文地址:https://blog.csdn.net/weixin_45614076/article/details/126315727