System Verilog学习笔记—随机化约束的控制

目录

1.控制多个约束块儿constraint_mode()

2.控制随机变量

2.1 rand_mode()

2.2 randomize() with {}

2.3 randomize单独控制变量

3.回调函数 pre_randomize和post_randomize

4.约束的重载(覆盖 )

4.1使用constraint_mode(0)关闭约束后用randomize_with{}重新定义约束

4.2子类extends父类,然后定义同名约束覆盖父类的约束 


1.控制多个约束块儿constraint_mode()

       如果在一个类中定义了多个约束块儿,以便为了后续根据实际需要打开所需的约束块儿时,该如何操作?(就像一个筋膜枪,你要根据实际需要调节频率(约束频率范围))

       具体讲解在代码注释中讲解

class Packet;
  rand int length;

//以下2个约束块儿互相排斥,切不可将2个约束块儿同时打开,否则会随机出错误结果
  constraint c_short//定义约束1<=length<=32
  {
    length inside {[1:32]};
  }

  constraint c_long //定义约束1000<=length<=1023
  {
    length inside {[1000:1023]};
  }
endclass

program test;
  Packet p;

  initial begin
    p = new();
    p.c_short.constraint_mode(0); //关闭c_short约束块儿
    assert(p.randomize());//此时length只在1000-1023中随机
    $display("P:length is %d",p.length);//1000-1023
   
    p.constraint_mode(0); //关闭所有约束条件
    p.c_short.constraint_mode(1); //打开c_short约束
    assert(p.randomize());//此时length只在1-32中随机
    $display("P:length is %d",p.length);//1-32
  end
endprogram

2.控制随机变量

2.1 rand_mode()

     如果我们在一个类中定义了n个随机变量,在后续调用该类的时候,我们想根据实际需要控制类中的某个变量是否要随机化,该如何操作?

     关键词:类实例化名.变量名.rand_mode(0关闭/1开启)

class Packet;
  rand bit [7:0] length, payload[];

  constraint c_valid 
  {
    length > 0;
    payload.size() == length;
  }
endclass

program test;
  Packet p;

  initial begin
    p = new();

    p.length.rand_mode(0); //关闭length的随机功能
    p.length = 42; //未现在不随机的length赋值
    $display("P:length is %d",p.length);//42

    assert (p.randomize());
    p.length.rand_mode(1); //打开length的随机功能
    $display("P:length is %d",p.length);//0-255
  end
endprogram

2.2 randomize() with {}

        如果我们定义了一个类,在后续调用时想在原来约束的基础上进一步加约束该如何操作?

        关键词:类实例化名.randomize()with{所需约束}

class Transaction;
  rand bit [31:0] addr, data;
  constraint c1 
  {
    addr inside{[0:100],[1000:2000]};
  }
endclass


program test;
  Transaction t;
  initial begin
    t = new();

    assert(t.randomize() with {addr >= 50; addr <= 1500; data < 10;});//在c1的基础上进一步约束范围
    $display("t::addr=%d,data=%d",t.addr,t.data);//addr is 50-100 or 1500-2000,data is 0-10

    assert(t.randomize() with {addr == 2000; data > 10;});//addr赋值2000,data大于10
    $display("t::addr=%d,data=%d",t.addr,t.data);//addr is 2000,data 大于10
end
endprogram

若外部所加约束与内部约束冲突,则看内部约束是否加了soft关键字,若加了则以外部约束为准,若没加则报错 

2.3 randomize单独控制变量

         该方法和2.1类似,都是对单个变量是否随机化进行操作,所不同的是操作方式

         关键词:类句柄.randomize(变量名)。表示只随机该变量,其它变量不随机

class Rising;
  byte low;
  rand byte med, hi;
  constraint c_up 
  {
    low < med; 
    med < hi;
  }
endclass

program test;
  Rising r;
  initial begin
    r = new();
    r.randomize(); //对所有随机变量在约束上进行随机
    r.randomize(med); //只随机med,hi保持上一个值
    r.randomize(low); //只随机low,但low不是随机变量,med和hi保持上一个值
  end
endprogram

3.回调函数 pre_randomize和post_randomize

     回调函数是指在父类中定义一个空方法,然后在不同子类中实现这些空方法

     他们都是function, 不消耗仿真时间;

     只要调用了randomize函数,在执行randomize函数之前先执行pre_randomize函数,再执行randomize函数,最后执行post_randomize函数。他们通常用来设置一些非随机的变量或者计算随机数据中的错误,如果如randomize调用失败,那么post_randomize将不会被执行,但是pre_randomize不管 randomize是否成功都会执行。

class wr_tran;
  int constraint_en;
  int broadcast;
  rand int wr_addr;
  rand int wr_data;
  rand bit valid;

  constraint generic_c 
  { 
    valid ==1; 
    wr_addr<100;
  }

  function void pre_randomize();//定义预处理函数
    $display("call the pre_randomize !");
    if(!constraint_en) 
      generic_c.constraint_mode(0);
  endfunction

  function void post_randomize();//定义后处理函数
    $display("call post_randomize !");
    if(wr_addr ==1) 
      broadcast =1;
    else 
      broadcast =0;
  endfunction
endclass

module m1;
  wr_tran tr;

  initial begin
    tr =new();

    tr.constraint_en=0;//为pre_randomize提供条件

    tr.randomize() with {tr.wr_addr==200;tr.wr_data==3;tr.valid==0;};
    $display("tr.wr_addr=%d,tr.wr_data=%d,tr.valid=%d,tr.broadcast=%d",tr.wr_addr, tr.wr_addr,tr.valid,tr.broadcast);
  end
endmodule

执行结果如图所示: 

 可见先打印了pre中的字符串,然后执行randomize为几个变量定值,然后执行post函数打印字符串,由于wr_addr 赋值为3,所以broadcas为0。

4.约束的重载(覆盖 )

4.1使用constraint_mode(0)关闭约束后用randomize_with{}重新定义约束

       具体解释见下面代码注释

class constrainend;
  rand bit x;
  rand bit [1:0] y;

  constraint c_xy //对x,y定义约束
  {
    (x==0)-> y==0;
  }
endclass

program test;
  constrainend p;

  initial begin
    p=new();

    p.c_xy.constraint_mode(0); 将实例p中对x,y的约束关闭

    assert(p.randomize() with {x==0; y==0;});//随机化x,y,并添加一个新约束

    $display("x = %d",p.x);//不会再被原类中的约束限制,而是被randomzie_with约束限制
    $display("y = %d",p.y);
  end
endprogram

4.2子类extends父类,然后定义同名约束覆盖父类的约束 

        具体解释见下面代码注释

class constrainend;
  rand bit x;
  rand bit [1:0] y;

  constraint c_xy 
  {
    (x==0)-> y==0;
  }
endclass

class overwrite extends constrainend;//子类继承父类,会继承属性和方法,所以父类的约束也继承了
  constraint c_xy//子类如果想定义一个新约束覆盖父类,则需要定义一个同名约束
  {
    x==0; 
    y==0;
  }
endclass

program test;
  overwrite p;

  initial begin
    p=new();

    assert(p.randomize());//在子类约束的基础上随机化

    $display("x = %d",p.x);
    $display("y = %d",p.y);
  end
endprogram

你可能感兴趣的:(SV学习笔记,systemverilog)