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

执行结果如下,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

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

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

其输出结果是:
在这里插入图片描述
但是若把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

例中,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

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

有约束的随机化(Constrained)

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

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

声明的形式如下:

constraint <constraint_block_name> { <condition/expression>; 
                                              ...
                                    <condition/expression>; }
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

在上面的例子中将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

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

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值