SV -- Randomization 随机化
@(SV)
0. 基础
下面几种类型可以随机化:
- 单个变量或整形数
- 数组
- 数组长度
- 对象句柄
语法:
rand bit [3:0] addr;
生成0-15的随机数randc bit [3:0] addr;
生成0-15的随机数,完全遍历完16个数之后才会开始开始下一轮,每一轮随机的数不重样object.randomize();
对象内变量随机化命令
rand_mode:
<object_hanlde>.<variable_name>.rand_mode(enable);
打开或关闭某个变量的随机化,或者
<object_hanlde>.rand_mode(enable);
打开或关闭某个类内的所有变量的随机化。
class packet;
rand byte addr;
rand byte data;
endclass
module rand_methods;
initial begin
packet pkt;
pkt = new();
//disable rand_mode of addr variable of pkt
pkt.addr.rand_mode(0);
//calling randomize method
pkt.randomize();
$display(" addr = %0d data = %0d",pkt.addr,pkt.data);
$display(" addr.rand_mode() = %0d data.rand_mode() = %0d",pkt.addr.rand_mode(),pkt.data.rand_mode());
end
endmodule
输出:
addr = 0 data = 110
addr.rand_mode() = 0 data.rand_mode() = 1
1. 随机化方法
- randomize()
- pre_randomize()
- 可以为类设置随机化的先决条件,例如rand_mode()
- post_randomize()
- 用来在随机化后进行检查
例如下面的例子,如果在wr_rd为1的时候,address需要保持不变,定义一个pre_randomize方法来控制变量是否随机化。
//class
class packet;
rand bit [7:0] addr;
randc bit wr_rd;
bit tmp_wr_rd;
//pre randomization function - disabling randomization of addr,
//if the prevoius 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) pkt.randomize();
end
endmodule
输出:
POST_RANDOMIZATION:: Addr = 6e,wr_rd = 1
POST_RANDOMIZATION:: Addr = 6e,wr_rd = 0
POST_RANDOMIZATION:: Addr = 88,wr_rd = 1
POST_RANDOMIZATION:: Addr = 88,wr_rd = 0
2. Constraint
为随机变量设置约束:
第一种,在内部设置:
class packet;
rand bit [3:0] addr;
constraint addr_range { addr > 5; }
endclass
第二种,在外部设置:
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; }
同样,constraint也会被子类继承。
3. inside
让随机值约束在inside指定的范围内:
constraint addr_range { addr inside {1,3,[5:10],12,[13:15]}; }
constraint addr_range { addr !(inside {[5:10]}); }
也可以将上下界指定为随机值(上下界都可以取到):
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
4. dist
可以使得随机化的数据
constraint addr_1_range { addr_1 dist { 2 := 5, [10:12] := 8 }; }
上面的权重是这样的:
addr == 2 , weight 5
addr == 10, weight 8
addr == 11, weight 8
addr == 12, weight 8
constraint addr_2_range { addr_2 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
5. 条件约束
class packet;
rand bit [3:0] addr;
string addr_range;
constraint address_range { if(addr_range == "small")
addr < 8;
else
addr > 8;
}
endclass
6. foreach 约束
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
7. disable constraint
跟randomize_mode一样,constraint也可以设置mode控制是否添加约束:
pkt.addr_range.constraint_mode(0);
0表示关闭约束
7. static constraint
静态约束跟普通约束不同的是,静态约束的使能和关闭对所有实例都生效:
class packet;
rand bit [7:0] addr;
static constraint addr_range { addr == 5; }
endclass
如果下面实例化了两个packet:a1和a2,如果对a1的addr变量设置constraint_mode(0),则a2的addr的约束也会关闭。
8. inline constraint
inline的约束允许使用with关键字在类外对变量增加新的约束:
class packet;
rand bit [3:0] addr;
constraint addr_range {addr inside {[6:12]};};
endclass
module inline_constr;
initial begin
packet pkt;
pkt = new();
repeat(2) begin
pkt.randomize() with { addr == 8;};
$display(" addr = %0d",pkt.addr);
end
end
endmodule
上面pkt.randomize() with { addr == 8;};
将给变量添加新的约束,使得输出都为8,但是通过with添加的新约束必须包含在类中定义的范围内,否则会报错。
9. soft constraint
软约束是为了解决inline方式的弊端。比如有这样的场景,我们已经测试了很多正常约束的case,可能会使用with的方式来生成约束的子集,但我们永远无法通过with来生成约束的补集,而这可能在测试异常情况时需要用到。一个方法是修改constraint,但无疑会有很大麻烦。
这时只需要在constraint中为变量增加soft关键字即可:
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(" addr = %0d",pkt.addr);
end
end
endmodule
10. unique
使用unique关键词加在一组随机变量或者随机数组前,可以使得这些变量在约束范围内各不相同:
rand bit [31:0] array[10];
constraint array_c {unique {array}; foreach(array[i]) array[i] < 10;}
11. 约束的双向性质
上面的例子一般都只涉及单个变量的约束,而实际上sv中约束的变量是并行地设置的,因此约束中如果涉及多个约束变量的约束,则这一约束是双向的。
例如:
constraint c_name { if(a == 0) b == 1;
else b == 0; }
上面的例子b的值依赖a,而实际上a的值也会依赖b,如果将b通过inine的方式约束为1,则a也被约束为0。
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 b = %0d",pkt.a,pkt.b);
end
endmodule
上面的例子试图用inline的方式约束b,但b的约束会反作用到a,使得a约束为0,但a已经约束为只能为1,所以程序报错。
12. Solve before
solve before可以强制约束中先进行哪个变量的约束。
在上面提到的约束双向性中,多个变量之间有依赖关系时约束是双向的,这可能会导致一些问题,比如下面的例子:
class packet;
rand bit a;
rand bit [3:0] b;
constraint a_b { (a == 1) -> b == 0; }
endclass
module inline_constr;
initial begin
packet pkt;
pkt = new();
repeat(10) begin
pkt.randomize();
$display(" Value of a = %0d, b = %0d",pkt.a,pkt.b);
end
end
endmodule
b可以取0-15中的值,而只要b不为0,a都会被约束为0,所以这个例子产生的结果是这样的:
Value of a = 0, b = 6
Value of a = 0, b = 3
Value of a = 1, b = 0
Value of a = 0, b = 15
Value of a = 0, b = 7
Value of a = 0, b = 2
Value of a = 0, b = 15
Value of a = 0, b = 4
Value of a = 0, b = 7
Value of a = 0, b = 11
a=1的情况非常少。如果我们希望a的产生不依赖b,可以使用solve before:
class packet;
rand bit a;
rand bit [3:0] b;
constraint sab { solve a before b;}
constraint a_b { (a == 1) -> b == 0;}
endclass
module inline_constr;
initial begin
packet pkt;
pkt = new();
repeat(10) begin
pkt.randomize();
$display(" Value of a = %0d, b = %0d",pkt.a,pkt.b);
end
end
endmodule
输出:
Value of a = 0, b = 9
Value of a = 0, b = 14
Value of a = 0, b = 3
Value of a = 0, b = 13
Value of a = 1, b = 0
Value of a = 1, b = 0
Value of a = 1, b = 0
Value of a = 0, b = 5
Value of a = 0, b = 3
Value of a = 0, b = 4
13. 随机系统函数
随机化的系统函数主要有两个:
- urandom() 生成无符号随机数,括号内可以填入不同随机种子
- urandom_range(max,min) 生成范围内的随机数,上下界可以不按顺序写,默认下届为0
- random() 生成有符号随机数。
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);
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
输出:
addr1=303379748, addr2=2153631232, addr3=423959822444962108, data=546103870
addr1=27, addr2=6, addr3=25