SV之随机化和约束

目录

Randomization 随机化

 Randomization Methods  随机化方法

Array Randomization 数组随机化 

Constraint Blocks 约束块

 External Constraint blocks  外部约束块

Constraint Inheritance  约束的继承

inside操作符

Weighted Distribution 权重分布

conditional constrain 条件约束

静态约束

Iterative in Constraint Blocks 迭代约束

constraint_mode( )

Inline Constraints 附加约束

Soft Constraints  软约束

Unique Constraint 唯一约束

Bidirectional Constraints 双向约束

Random System Methods SV中的随机化函数


Randomization 随机化

类中的变量可以使用关键字rand和randc来随机化取值;SV中以下的几种类型数据可以被rand和randc修饰:

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

(1)rand

rand bit [3:0] addr;//随机化范围根据位宽为0~15

 此时0~15内的任意整数被取到的概率都是等同的;

(2)randc  (random cyclic)

randc bit   wr_rd;

randc表示周期性随机,即所有的可能值都取过之后随机值才可能重复; 

(3)randomize()方法

用来对象的随机化,格式如下:

object.randomize();//如果随机化成功,则返回1,否则返回0

下面举例说明:

//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("\taddr1 = %0d \t addr2 = %0d",pkt.addr1,pkt.addr2);
    end
  end
endmodule

addr1的随机类型为rand, addr2的随机类型为randc,输出结果如下:

SV之随机化和约束_第1张图片

(4)rand_mode()

通过修改rand_mode()的参数值,可以允许或禁止随机化;默认情况下的参数为1;语法格式如下:

 addr.rand_mode(0); //参数为0表示禁止随机化
 packet.addr.rand_mode(0);

对象名.成员名.rand_mode(0);//关闭成员的随机化
对象名.rand_mode(0);//关闭所有成员的随机化
class Fruits;
  rand bit [3:0] var1;
  rand bit [1:0] var2;
endclass

module tb;
  initial begin
    Fruits f = new(); 
    $display ("Before randomization var1=%0d var2=%0d", f.var1, f.var2);
    
    
    f.var1.rand_mode (0);// 关闭var1的随机化
    
    // Print if var1 has randomization enabled/disabled
    if (f.var1.rand_mode())
      $display ("Randomization of var1 enabled");
    else
      $display ("Randomization of var1 disabled");
    
    f.randomize();
    
    $display ("After randomization var1=%0d var2=%0d", f.var1, f.var2);
  end
endmodule

SV之随机化和约束_第2张图片

// Create a class that contains random variables
class Fruits;
  rand bit [3:0] var1;
  rand bit [1:0] var2;
endclass
 
module tb;
 
  initial begin
    Fruits f = new(); 
    $display ("Before randomization var1=%0d var2=%0d", f.var1, f.var2);
 
    // Turns off randomization for all variables
    f.rand_mode (0); //不带成员变量名后关闭的是所有成员变量的随机化   
 
    if (! f.var1.rand_mode())
      if (! f.var2.rand_mode())
        $display ("Randomization of all variables disabled");
 
    f.randomize();
 
    $display ("After randomization var1=%0d var2=%0d", f.var1, f.var2);
  end
endmodule

SV之随机化和约束_第3张图片 因为关闭了随机化,所以两个变量都是默认值.

 Randomization Methods  随机化方法

随机化方法randomize( )是一个虚方法,在遵守有效约束的情况下为对象的所有随机化变量产生随机值;如果随机化成功,该方法会返回1,否则返回0

其次,每个类都包括内建的pre_randomize()post_randomize()方法.一旦调用randomize( ),会在随机化的前后分别调用pre_randomize()post_randomize()方法.用户可以自定义这两个方法以覆盖内建的方法,这两个方法虽然不是虚方法,但是表现和虚方法类似,当你试图在这两个方法前加上virtual关键字时会报错

pre_randomize()可以用来在随机化之前设置一些随机化的条件,例如阻止某些随机变量的随机化;pre_randomize()可以用来在随机化之后检查对象随机化之后的后置条件,如打印随机化的值或者覆盖随机化的值等。

看下面的例子,包括两个随机化变量addr 和wr_rd.

约定:wr_rd=0,执行读操作;wr_rd=1,执行写操作;

为了在读操作之后写入读操作的同一个地址,addr的随机化被wr_rd的前一个随机值所控制

//class
class packet;
  rand  bit [7:0] addr;
  randc bit       wr_rd;
  bit       tmp_wr_rd;    
 
  //pre randomization function - 控制addr是否随机化
  //if the prevoius operation is write.
  function void pre_randomize();
    if(tmp_wr_rd==1) addr.rand_mode(0);//如果前一个操作是写,则阻止随机化addr
    else                 addr.rand_mode(1);
  endfunction
 
  //post randomization function - 将wr_rd的值存入tmp_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) pkt.randomize();
  end
endmodule

 运行结果如下:

SV之随机化和约束_第4张图片当前一个wr_rd为1时,addr不进行随机化;

Array Randomization 数组随机化 

SV可以对定宽数组、动态数组、队列进行随机化.

(1)定宽数组 

class Packet;
  rand bit [3:0]   s_array [7];   // Declare a static array with "rand"
endclass
 
module tb;
  Packet pkt;
 
  // Create a new packet, randomize it and display contents
  initial begin
    pkt = new();
    pkt.randomize();//调用随机方法
    $display("queue = %p", pkt.s_array);
  end 
endmodule

 SV之随机化和约束_第5张图片

(2)动态数组

class Packet;
  rand bit [3:0]   d_array [];   // Declare a dynamic array with "rand"
 
  // Constrain size of dynamic array between 5 and 10  约束动态数组的长度
  constraint c_array { d_array.size() > 5; d_array.size() < 10; }
 
  // Constrain value at each index to be equal to the index itself
  constraint c_val   { foreach (d_array[i]) 
              d_array[i] == i; 
                     }//对数组元素的约束,要对每一个元素约束
 
  // Utility function to display dynamic array contents
  function void display();
    foreach (d_array[i]) 
      $display ("d_array[%0d] = 0x%0h", i, d_array[i]);
  endfunction
endclass
 
module tb;
  Packet pkt;
 
  // Create a new packet, randomize it and display contents
  initial begin
    pkt = new();
    pkt.randomize();//在调用随机化函数时默认对动态数组new
    pkt.display();
  end 
endmodule

 结果:

SV之随机化和约束_第6张图片

(3)队列

class Packet;
  rand bit [3:0]   queue [$];   // Declare a queue with "rand"
 
  // Constrain size of queue between 5 and 10   约束队列的长度
  constraint c_array { queue.size() == 4; }//约束中不允许存在赋值,约束内部的赋值用"=="代替
endclass
 
module tb;
  Packet pkt;
 
  // Create a new packet, randomize it and display contents
  initial begin
    pkt = new();
    pkt.randomize();
 
    // Tip : Use %p to display arrays
    $display("queue = %p", pkt.queue);
  end 
endmodule

 结果:

Constraint Blocks 约束块

随机变量可以通过随机化获得随机值,通过对随机变量添加约束可以得到特定范围内的随机值 ;约束必须写在约束块中.

约束块是类的成员,就像成员变量和成员方法一样,类里面的每一个约束块都要有唯一的块名,如:

constraint addr_range { addr > 5; }

adde_range是约束块名,约束的所有语句都被大括号{ }包围起来(这与语句块不同,语句块为begin...end),每条语句后面都要加分号";"。约束的通用格式如下:

constraint  [name_of_constraint] {  [expression 1];
                                      [expression N]; 
                                 }

看下面例子:

class packet;
  rand  bit [3:0] addr;
 
  constraint addr_range { addr > 5; }//限定addr的值大于5
endclass
 
module constr_blocks;
  initial begin
    packet pkt;
    pkt = new();
    repeat(10) begin
      pkt.randomize();
      $display("\taddr = %0d",pkt.addr);
    end
  end
endmodule

 结果如下:

SV之随机化和约束_第7张图片

 External Constraint blocks  外部约束块

约束可以像方法一样,在类的内部声明,而在类的外部定义,要使用作用域操作符"::"。

看下面例子:

class packet;
  rand  bit [3:0] addr;
//constraint block declaration
  constraint addr_range;
endclass
 
//constraint implementation outside class body 约束在类外部定义时,注意添加类名和作用域操作符
constraint packet::addr_range { addr > 5; }
 
module extern_constr;
  initial begin
    packet pkt;
    pkt = new();
 
    repeat(10) begin
      pkt.randomize();
      $display("\taddr = %0d",pkt.addr);
    end
  end
endmodule

运行结果:

SV之随机化和约束_第8张图片

Constraint Inheritance  约束的继承

与类的成员一样,类的约束一样能被子类继承和覆盖重写.

class packet;
  rand  bit [3:0] addr;
  constraint addr_range { addr > 5; }
endclass
 
class packet2 extends packet;
  constraint addr_range { addr < 5; } //同名约束,覆盖了父类的约束;要重写同名约束,约束的内容要与父类中的同名约束不同。函数也是如此
 //constraint addr_range1 { addr < 5; } //非同名约束,与父类的原有约束叠加
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

运行结果:

SV之随机化和约束_第9张图片

inside操作符

可以用inside操作符产生一个随机数的集合,随机变量的取值在这个集合里面选取,且每个值取到的概率均等.如下:

constraint addr_range  { addr inside {1,3,5,7,9}; }
constraint addr_range  { addr inside {[5:10]}; }
constraint addr_range  { addr inside {1,3,[5:10],12,[13:15]}; }
constraint addr_range  { addr !(inside {[5:10]}); }//对范围取反

集合可以是范围,也可以是多个数的列举,还可以对范围进行取反操作等等.  

 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]}; }//范围的边界也可以是随机值

看下面例子:

class packet;
  rand bit [3:0] addr_1;
  rand bit [3:0] addr_2;
  rand bit [3:0] start_addr;
  rand bit [3:0] end_addr;
  constraint addr_1_range {   addr_1 inside {[start_addr:end_addr]}; }
  constraint addr_2_range { !(addr_2 inside {[start_addr:end_addr]}); }
endclass
 
module constr_inside;
  initial begin
    packet pkt;
    pkt = new();
 
    $display("------------------------------------");
    repeat(3) begin
      pkt.randomize();
      $display("\tstart_addr = %0d,end_addr = %0d",pkt.start_addr,pkt.end_addr);
      $display("\taddr_1 = %0d",pkt.addr_1);
      $display("\taddr_2 = %0d",pkt.addr_2);
      $display("------------------------------------");
    end
  end
endmodule

结果如下:

SV之随机化和约束_第10张图片

Weighted Distribution 权重分布

dist操作符允许产生随机数的权重分布,这样不同的值选取的概率就会不同 。dist操作符带有一个值的列表以及相应的权重,中间用:=或:/分开.值或权重可以是常数或者变量,值也可以是一个数或范围,如[lo,hi]。权重不用百分比表示,权重的和也不必是100。:=操作符表示值范围内的每个值的权重是相同的,:/表示权重要均分到每个值.

addr dist { 2 := 5, [10:12] := 8 };
         //addr = 2 , weight 5
        // addr = 10, weight 8
         //addr = 11, weight 8
         //addr = 12, weight 8
 addr dist { 2 :/ 5, [10:12] :/ 8 };
         //addr = 2 , weight 5
        // addr = 10, weight 8/3
        // addr = 11, weight 8/3
         //addr = 12, weight 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("\taddr = %0d",pkt.addr);
    end
    $display("------------------------------------");
  end
endmodule

输出结果:

SV之随机化和约束_第11张图片

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("\taddr_1 = %0d",pkt.addr_1);
    end
    $display("------------------------------------");
    $display("------------------------------------");
    repeat(10) begin
      pkt.randomize();
      $display("\taddr_2 = %0d",pkt.addr_2);
    end
    $display("------------------------------------");
  end
endmodule

输出结果:

 SV之随机化和约束_第12张图片

通过solve...before改变权重

class ABC;
  rand  bit      a;
  rand  bit [1:0]   b;
 
  constraint c_ab { a -> b == 3'h3; }
endclass
 
module tb;
  initial begin
    ABC abc = new;
    for (int i = 0; i < 8; i++) begin
      abc.randomize();
      $display ("a=%0d b=%0d", abc.a, abc.b);
    end
  end
endmodule

各种值的概率:

SV之随机化和约束_第13张图片

在约束中加上solve..before的情况:

class ABC;
  rand  bit      a;
  rand  bit [1:0]   b;
 
  constraint c_ab { a -> b == 3'h3; 
 
            // Tells the solver that "a" has
            // to be solved before attempting "b"
            // Hence value of "a" determines value 
            // of "b" here
                    solve a before b;
                  }
endclass
 
module tb;
  initial begin
    ABC abc = new;
    for (int i = 0; i < 8; i++) begin
      abc.randomize();
      $display ("a=%0d b=%0d", abc.a, abc.b);
    end
  end
endmodule

取值概率:

SV之随机化和约束_第14张图片

conditional constrain 条件约束

 (1)-> 操作符

语法格式:

expression -> constraint
//如果表达式为真,则执行约束

举例:

class packet;
  rand bit [3:0] addr;
       string    addr_range;
  constraint address_range { (addr_range == "small") -> (addr < 8);}// irun好像不支持在约束中使用字符串,改为枚举就OK了
endclass
 
module constr_implication;
  initial begin
    packet pkt;
    pkt = new();
 
    pkt.addr_range = "small";
    $display("------------------------------------");
    repeat(4) begin
      pkt.randomize();
      $display("\taddr_range = %s addr = %0d",pkt.addr_range,pkt.addr);
    end
    $display("------------------------------------");
  end
endmodule

运行结果:

SV之随机化和约束_第15张图片

class ABC;
  rand bit [2:0] mode;
  rand bit [3:0] len;
 
  constraint c_mode { mode == 2 -> len > 10; }//如果mode为2,则len>10
endclass
 
module tb;
  initial begin
    ABC abc = new;
    for(int i = 0; i < 10; i++) begin
      abc.randomize();
      $display ("mode=%0d len=%0d", abc.mode, abc.len);
    end
  end
endmodule

结果:

SV之随机化和约束_第16张图片

(2)if...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("\taddr_range = %s addr = %0d",pkt.addr_range,pkt.addr);
    end
    $display("------------------------------------");
 
    pkt.addr_range = "high";
    $display("------------------------------------");
    repeat(3) begin
      pkt.randomize();
      $display("\taddr_range = %s addr = %0d",pkt.addr_range,pkt.addr);
    end
    $display("------------------------------------");
  end
endmodule

结果:

SV之随机化和约束_第17张图片

静态约束

与静态成员一样,约束同样可以定义为static。静态约束在所有类的对象之间共享,也就是说如果某个对象关闭了静态约束,那么其他对象的静态约束也被关闭。静态约束格式如下:

class [class_name];
  ...
 
  static constraint [constraint_name] [definition]
endclass

看下面例子:

class ABC;
  rand bit [3:0]  a;
 
  // "c1" is non-static, but "c2" is static
  constraint c1 { a > 5; }//非静态约束
  static constraint c2 { a < 12; }//静态约束
endclass
 
module tb;
  initial begin
    ABC obj1 = new;
    ABC obj2 = new;
 
    // Turn off non-static constraint
    obj1.c1.constraint_mode(0);//关闭obj1的非静态约束
 
    for (int i = 0; i < 5; i++) begin
      obj1.randomize();
      obj2.randomize();
      $display ("obj1.a = %0d, obj2.a = %0d", obj1.a, obj2.a);
    end
  end
endmodule

 由于关闭了obj1对象的非静态约束,所以obj1.a的值被限定在a<12的范围内,输出结果如下:

SV之随机化和约束_第18张图片

class ABC;
  rand bit [3:0]  a;
 
  // "c1" is non-static, but "c2" is static
  constraint c1 { a > 5; }
  static constraint c2 { a < 12; }
endclass
 
module tb;
  initial begin
    ABC obj1 = new;
    ABC obj2 = new;
 
    // Turn non-static constraint
    obj1.c2.constraint_mode(0);//关闭静态约束
 
    for (int i = 0; i < 5; i++) begin
      obj1.randomize();
      obj2.randomize();
      $display ("obj1.a = %0d, obj2.a = %0d", obj1.a, obj2.a);
    end
  end
endmodule

由于obj2对象关闭了静态约束,所以obj1和obj2都只激活了c1约束,也就是a>5,所以结果如下:

SV之随机化和约束_第19张图片

Iterative in Constraint Blocks 迭代约束

迭代约束允许使用循环变量和索引表达式约束数组变量,如:

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; }

例子:

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; }//如果改为大于4,irun会报错?这里发现数组深度的约束只能是小于某一个特定值,若改为大于则会报错,不知道原因;之后在写数组深度的约束时,需要设定一个深度上限,否则很可能会报错
  constraint dsize   { data.size == addr.size; } //在约束中,== 表示赋值
endclass
 
module constr_iteration;
  initial begin
    packet pkt;
    pkt = new();
 
    $display("------------------------------------");
    repeat(2) begin
      pkt.randomize();
      $display("\taddr-size = %0d data-size = %0d",pkt.addr.size(),pkt.data.size());
      foreach(pkt.addr[i]) $display("\taddr = %0d data = %0d",pkt.addr[i],pkt.data[i]);
      $display("------------------------------------");
    end
  end
endmodule

结果:

SV之随机化和约束_第20张图片

constraint_mode( )

 constraint_mode()方法可以用来禁止约束,默认情况下该方法的参数值为1,表示约束有效;参数为0时,表示约束无效.

addr_range.constraint_mode(0); //设置约束无效
packet.addr_range.constraint_mode(0);//packet为类名
class Fruits;
  rand bit[3:0]  num; 				// Declare a 4-bit variable that can be randomized
  
  constraint c_num { num > 4;  		// Constraint is by default enabled, and applied
                    num < 9; }; 	// during randomization giving num a value between 4 and 9
endclass

module tb;
  initial begin
    Fruits f = new ();
    $display ("Before randomization num = %0d", f.num); 	
    
    // Disable constraint 
    f.c_num.constraint_mode(0);//关闭约束
    
    if (f.c_num.constraint_mode ())
      $display ("Constraint c_num is enabled");
    else
      $display ("Constraint c_num is disabled");
      
    // Randomize the variable and display
    f.randomize ();
    $display ("After randomization num = %0d", f.num);    
  end
endmodule

 SV之随机化和约束_第21张图片由于关闭了约束,所以随机化后num=15.

也可以设置静态约束,只需要在约束前加上static关键字 ,这是任何对约束的改变都会反映到类例化的每一个对象上,例如禁止某一对象的约束有效,其余对象的约束也同时无效了.

static constraint addr_range { addr > 5; }

例子:

class packet;
  rand  bit [3:0] addr;
 
  static constraint addr_range { addr > 5; }
endclass
 
module static_constr;
  initial begin
    packet pkt1;
    packet pkt2;
 
    pkt1 = new();
    pkt2 = new();
 
    pkt1.randomize();
    $display("\taddr = %0d",pkt1.addr);
    pkt1.addr_range.constraint_mode(0);
    $display("\tAfter disabling constraint");
    pkt1.randomize();
    $display("\taddr = %0d",pkt1.addr);
    pkt2.randomize();
    $display("\taddr = %0d",pkt2.addr);
  end
endmodule

结果:

SV之随机化和约束_第22张图片

Inline Constraints 附加约束

(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;};//在调用randomize方法时添加约束
      $display("\taddr = %0d",pkt.addr);
    end
  end
endmodule

结果:

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("\taddr = %0d data = %0d",pkt.addr,pkt.data);
    end
  end
endmodule

结果:

SV之随机化和约束_第23张图片

 (2)附加的约束函数

class packet;
  rand bit [3:0] start_addr;
  rand bit [3:0] end_addr;
 
  constraint end_addr_c { end_addr == e_addr(start_addr); }//调用约束函数
 
  function bit [3:0] e_addr(bit [3:0] s_addr);
    if(s_addr<0)
      e_addr = 0;
    else
        e_addr = s_addr * 2;
  endfunction
endclass
 
module func_constr;
  initial begin
    packet pkt;
    pkt = new();
 
    repeat(3) begin
      pkt.randomize();
      $display("\tstart_addr = %0d end_addr =",pkt.start_addr,pkt.end_addr);
    end
  end
endmodule

结果:

Soft Constraints  软约束

举个例子,父类中的约束为constraining a < 10,子类中的约束为 constraining a > 10,这样两个约束会发生互斥而导致随机化的失败.解决这一问题的方法就是使用软约束,格式如下:

constraint c_name { soft variable { condition }; }

例子:

class packet;
  rand bit [3:0] addr;
  constraint addr_range { addr > 6; }
endclass
 
module soft_constr;
  initial begin
    packet pkt;
    pkt = new();
 
    repeat(2) begin
      pkt.randomize() with { addr < 6;};//内嵌约束与类中的约束矛盾,会导致随机化失败
      $display("\taddr = %0d",pkt.addr);
    end
  end
endmodule

 结果:

SV之随机化和约束_第24张图片报错后,addr被赋予默认值.

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("\taddr = %0d",pkt.addr);
    end
  end
endmodule

结果:

当正常约束与软约束发生矛盾时,软约束被正常约束抑制 .

Unique Constraint 唯一约束

在随机化过程中,可以使用唯一约束生成变量集或数组中唯一元素的唯一值 .

唯一约束允许:

  • 跨变量生成唯一值;
  • 在数组中生成唯一元素

 例子:

class unique_elements;
  rand bit [3:0] var_1,var_2,var_3;
  rand bit [7:0] array[6];
   
  constraint array_c {unique {array};}//唯一约束,关键字unique
   
  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

结果:

SV之随机化和约束_第25张图片

Bidirectional Constraints 双向约束

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

 结果:

SV之随机化和约束_第26张图片第二组 a 已经溢出。

class packet;
  rand bit a;
  rand bit b;
 
  constraint a_value { a == 1; }
  constraint b_value { if(a == 0) b == 1;
                       else       b == 0; }
endclass
 
module bidirectional_const;
  initial begin
    packet pkt;
    pkt = new();
    pkt.randomize() with { b == 1; };//内嵌约束与前面的约束发生矛盾
    $display("Value of a = %0d \tb = %0d",pkt.a,pkt.b);
  end
endmodule

结果:

SV之随机化和约束_第27张图片

由于约束发生矛盾,所以报错.

Random System Methods SV中的随机化函数

 (1) $urandom( ) 

 $urandom( ) 方法返回一个32bit的无符号整型数据,格式如下:

variable = $urandom(seed);//seed种子是个可选项
bit [31:0] addr1;
   bit [31:0] addr2;
   bit [64:0] addr3;
   bit [31:0] data;

   addr1 = $urandom();
   addr2 = $urandom(89);
   addr3 = {$urandom(),$urandom()};
   data  = $urandom * 6;

(2)  $random( )

$urandom( )类似,但是返回的是带符号数据.

(3) $urandom_range( ) 

 返回一定范围的无符号数据,格式如下:

 $urandom_range( int unsigned maxval, int unsigned minval = 0 );
addr1 = $urandom_range(30,20);
addr2 = $urandom_range(20); //默认最小值为0
addr3 = $urandom_range(20,30); //considers max value as '30' and min value as '20'

 例子:

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);//89 表示seed
    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

结果:

你可能感兴趣的:(systemverilog)