当前位置:   article > 正文

System Verilog — 随机化_systemverilog dist

systemverilog dist

一、随机约束和分布

  • rand表示每次随机化这个类时,这些变量都会赋一个值。
  • randc表示周期随机性,即所有可能的值都赋过后随机值才可能重复。
  • 随机属性需要配合SV预定义的类随机函数randomize()使用。即只有通过声明rand变量,并且在后期通过对象调用randomize()函数才可以随机化变量。
Class Packet;
	//The random variables
	rand bit[31:0]src, dst, data[8];
	randc bit[7:0]kind;
	//Limit the values for src
	constraint c(src > 10;
				 src <15;);
endclass
Packet p;
initial begin
	p = new();//Create a packet
	assert(p.randomize()) else
	$fatal(0, "Packet::randomize failed");
	transmit(p);
end	
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

1.权重分布

  • 关键词dist可以在约束中用来产生随机数值的权重分布,这样某些值的选取机会要比其他值更大一些。
  • “:=”操作符表示值范围内的每一个值的权重是相同的,“:/"操作符表示权重均分到值范围内的每一个值。
  • 权重不用百分比表示,权重的和也不必是100。
  • 值和权重可以是常数或变量。
constraint c_dist{
	src dist {0:=40, [1:3]:=60};
	//src = 0, weight = 40/220
	//src = 1, weight = 60/220
	//src = 2, weight = 60/220
	//src = 3, weight = 60/220
	dst dist {0:/40, [1:3]:/60};
	//dst = 0, weight = 40/100
	//dst = 1, weight = 20/100
	//dst = 2, weight = 20/100
	//dst = 3, weight = 20/100
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.集合成员和inside运算符

使用inside运算符产生一个值的集合。

//随机值的集合
rand int c;//随机变量
int lo, hi;//作为上限和下限的非随机变量
constraint c_range{
	c_inside{[lo:hi]};// lo<=c且c<=hi
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以使用$来代表取值范围里的最小值和最大值。

rand bit[6:0]b;// 0<=b<=127
rand bit[5:0]e;// 0<=e<=63
constraint c_range{
	b_inside{[$:4], [20:$]};//0<=b<=4||20<=b<=127
	e_inside{[$:4], [20:$]};//0<=b<=4||20<=b<=63
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3.条件约束

通过->或者if-else来让一个约束表达式在特定时刻有效。

constraint c_io{
	(io_space_mode) ->
	addr[31] == 1'b1;
}
constraint c_len_rw{
	if(op == READ)
		len inside{[BYTE:LWRD]};
	else
		len == LWRD;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4.双向约束

SV的约束是双向的,这表示它会同时计算所有的随机变量的约束。增加或删除任一个变量的约束都会直接或间接影响所有相关变量的值的选取。

二、约束块控制

  • 一个类可以包括多个约束块。
  • 可以使用内建的constraint_mode()函数打开或关闭约束。(constraint_mode(0)禁止,constraint_mode(1)使能。)
  • 作为声明性的代码,约束块使用{}。

使用constraint_mode()函数。

class Packet;
	rand int length;
	constraint c_short {length inside {[1:32]};}
	constraint c_long {length inside {[1000:1023]};}
endclass

Packet p;
initial begin
	p = new();
	//通过禁止c_short约束产生长包
	p.c_short.constraint_mode(0);
	assert(p.randomize());
	transmit(p);

	//通过禁止所有的约束,然后使能短包来产生短包
	p.constraint_mode(0);
	p.c_short.constraint_mode(1);
	asser(p.randomize());
	transmit(p);
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

内嵌约束:SV允许使用randomize() with来增加额外的约束,这和在类里增加约束是等效的。

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

Transaction t;

initial begin
	t =new();
	// addr 范围:50-100,1000-1500 data < 10
	assert(t.randomize() with {addr >= 50; addr <= 1500;
							   data < 10;});
	driveBus(t);
	//强制addr取固定值,data > 10
	assert(t.randomize() with {addr == 2000; data > 10;});
	driveBus(t);
end
							 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

三、随机函数

SV可以使用两个特殊的void类型的pre_randomize()和post_randomize()函数在调用randomize()之前或之后执行一些操作。

  • $random():平均分布,返回32位有符号随机数。
  • $urandom():平均分布,返回32位无符号随机数。
  • $urandom_range():在指定范围内的平均分布。
a = $urandom_range(3, 10);//3~10
a = $urandom_range(10, 3);//3~10
b = $urandom_range(5);//0~5
  • 1
  • 2
  • 3

约束的技巧

  • 使用变量的约束
rand int size;
int max_size = 100;
constraint c_size{
	size inside{[1:max_size]};//通过改变max_size的值来改变随机变量size的上限
}
  • 1
  • 2
  • 3
  • 4
  • 5
//带有权重变量的dist约束
rand rand_e;
rand rand_cmd;
int read8_wt = 1, read16_wt = 1, read32_wt = 1;
constraint c_read{
	read_cmd dist{READ8:=read8_wt,
				  READ16:=read16_wt,
				  READ32:=rea32_wt};
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 使用非随机值

如果在用一套约束在随机的过程中已经产生了几乎所有想要的激励向量,但还是缺少几种激励向量,可以采用先调用randomize()函数,然后再把随机变量的值设置为固定的期望值的方法来解决。

p.length.rand_mode(0);//设置包长为非随机值
p.length = 42;//设置包长为常数
  • 1
  • 2
  • 随机化个别变量
class Rising;
	byte low;//not random
	rand byte med, hi;//random variable
	constraint up{low < med; med < hi;}
endclass
initial begin
	Rising r;
	r = new();
	r.randomize();//随机化hi,但不改变low
	r.randomize(med);//只随机化med
	r.randomize(low);//只随机化low
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 打开或关闭约束
    在约束的表达式较多时,可以对每一种指令建立一套独立的约束,在使用时关闭其他所有约束。
  • 定义外部约束
    外部约束对类的所有实例都起作用,而内嵌约束仅仅影响一次randomize()调用。
//带有外部约束的类
class Packet;
	rand bit[7:0]length;
	rand bit[7:0]payload[];
	constraint c_valid{length > 0;
					   payload.size() == length;}
	constraint c_external'
endclass

//test.sv
program automatic test;
	include"packet.sv" constraint Packet::c_external{length == 1;}
...
endprogram
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

四、数组约束

  • 约束动态数组的大小
class dyn_size;
	rand logic[31:0] d[];//随机化一个空数组
	constraint d_size {d.size() inside {[1:10]};}//进行约束
endclass
  • 1
  • 2
  • 3
  • 4
  • 多数情况下,数组的大小应该给定范围,防止生成过大体积的数组或者空数组。

  • SV可以利用foreach对数组的每一个元素进行约束。

class sum;
	rand unit len[];
	constraint c_len{foreach(len[i])
					 len[i] inside{[1:255]};
					 len.sum < 1024;
					 len.size() inside{[1:8]};}
endclass
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 产生具有唯一元素值的数组。

使用foreach产生唯一的元素值。

class UniqueSlow;
	rand bit[7:0] ua[64];
	constraint c{
		foreach(ua[i])//对数组的每个元素操作
			foreach(ua[j])
				if(i != j)//除了元素自己
					ua[i] != ua[j];//和其它元素比较(即与其他元素都不同)
	}
endclass
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

使用randc辅助类产生唯一的元素值。

class randc8;
	randc bit[7:0]val;
endclass

class LittleUniqueArray;
	bit[7:0]ua[64];
	function void pre_randomize;
		randc8 rc8;
		rc8 = new();
		foreach(ua[i])begin
			assert(rc8.randmize());
			ua[i] = rc8.val;
		end
	endfunction
endclass
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 随机化句柄数组
    如果要产生多个对象,需要建立随机句柄数组。和整数数组不同,需要在随机化前分配所有的元素。使用动态数组可以按照需要分配最大数量的元素,然后再使用约束减小数组的大小。在随机化时,动态句柄数组的大小可以保持不变或者减小,但不能增加。

五、随机控制

1.randsequence

  • 使用SV的randsequece来产生事务序列。
initial begin
	for(int i=0; i < 15; i++)begin
		randsequence(stream)
			stream:cfg_read :=1|
				   io_read :=2|
				   mem_read:= 5;
		    cfg_read:{cfg_read_task;}|
		    		 {cfg_read_task;} cfg_read;
		    io_read:{io_read_task;}|
		    		 {io_read_task;} io_read;
		    mem_read:{mem_read_task;}|
		    		 {mem_read_task;} mem_read;
		 endsequence
	end
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

上述的代码产生了stream序列,它可以是cfg_read,io_read或mem_read,随机序列会随机地从三种操作中选取一种,权重分别为1,2,5。

2.randcase

使用randcase的随机控制

initial begin
	int len;
	randcase
		1:len = $urandom_range(0, 2);//10%:0,1,2
		8:len = $urandom_range(3, 5);//80%:3,4,5
		1:len = $urandom_range(6, 7);//10%:6,7
	endcase
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/107116
推荐阅读
相关标签
  

闽ICP备14008679号