System Verilog的约束constraint

本文详细介绍了System Verilog的约束块(constraint block)的使用,包括简单表达式约束、权重取值(dist)、inside运算符以及条件约束。重点讲述了dist的两种权重分配方式和solve...before...的用法,强调了在randc修饰符下避免使用solve...before...的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


约束编程是system verilog中一个很强大的编程方法,它让我们创建的对象可以很轻松扩展功能或约束对象实现指定的功能

1、约束块(constraint block)

约束块是类的成员,像变量、task和function一样,约束块的名字在一个类里是唯一的,约束块的声明如下:

class bus;
	rand bit [31:0] addr,data
	constraint addr_c {
		addr[1:0] == 2'b0;
	}
endclass

上面的代码中构建了一个约束块addr_c,约束快的修饰符是constrain,约束的内容是地址的低2bit为0,在调用randomize()函数随机时,随机出的地址,低2bit一直为0;

class test_a;
	bus bus_a = new();
	task bus_test;
		repeat(50) begin
			if(bus_a.randomize() == 1)
				$display ("addr = %0h data = %h\n", bus.addr, bus.data);
			else
				$display ("Randomization failed.\n");
		end
	endtask
endclass

2、约束块的取值

A、简单表达式

在约束块中,只能使用关系操作符(<,<=,==, >=,>),一个表达式只能使用一个关系操作符。

class bus
	....
	constraint data_c { 
			data > 20;
			data<100;//不能写为20<data<100,这样一个表达式就有两个关系符,
	}
endclasss

等效表达式:==,表示约束的随机值取固定值,如上面的constrain addr_c,约束地址的低2bit取0

class bus
	....
	constraint data_c { data = 32'h5a5a_5a5a};//约束data的值恒为5a5a5a5a
endclasss

B、约束块权重取值:dist

使用dist操作符,可以是变量按我们设定的权重值随机,以增加某些值的随机概率,产生我们期望的激励,dist权重取值有两种写法:

1、:=取权重

class bus
	....
	constraint data_c { 
		data dist {0:=10,[1:3]:=80};
		//data = 0,权重为10/250,250=10+80*3;
		//data = 1/2/3的权重均为80/250;
	}
endclasss

2、:/取权重

class bus
	....
	constraint data_c { 
		data dist {0:/10,[1:3]:/90};
		//data = 0,权重为10/100;
		//data = 1/2/3的权重均为30/100;
	}
endclasss

C、inside运算符

inside运算符用于在集合set中取值,system verilog在集合中取值时,每个值取中的概率是相等的。

class bus
	....
	constraint data_c { 
		data inside {[$:5],[10:100]};
		//表示在0-5和10-100中取值,$表示边界值
		! (data inside {[110:200]});
		//表示取110-200之外的值
	}
endclasss

当集合set中的值有重复的时候,每个值取值概率也是一样的,不会因为某个值重复多次,概率就增加。

class bus
	....
	int array = '{1,2,2,3,3,3,4,4,4,4}
	constraint data_c { 
		data inside array;
		//此时,1,2,3,4取到的概率是相同的	
	}
endclasss

3、约束块中的条件约束

约束块中的条件约束有两种写法:

1、隐含操作符:->

typedef enum {low, mid, high} AddrType;
class bus
	......
	rand AddrType a_type ;
	constraint data_c { 
		(a_type == low) -> addr inside {[0:50]};
		(a_type == mid) -> addr inside {[60:70]};
		(a_type == high) -> addr inside {[80:100]};
	}
endclasss

2、if-else

typedef enum {low, mid, high} AddrType;
class bus
	......
	rand AddrType a_type ;
	constraint data_c { 
		if(a_type == low) 
			addr inside {[0:50]};
		esle if(a_type == mid) 
			addr inside {[60:70]};
		else if(a_type == high)
			addr inside {[80:100]};
	}
endclasss

3、约束块中的约束关系都是双向的

约束块代码不是自上而下的程序性代码,是声明性的代码,是并行的,所有的约束表达式同时有效。

class test;
	rand bit x;
	rand bit[1:0] y;
	cosntraint xy_c {
		y>0;
		(x==0) -> (y==0);
	}
endclass

上面代码中的,x为0时,y为0,但约束是双向的,y不为0时,x的取值不为0,解的概率如下:

xy概率xy概率
000100
010111/3
020121/3
030131/3

4、sovle…before…修改解的概率

sovle…before…不会改变解的个数和范围,只会改变各个值的概率分布。

class test;
	rand bit x;
	rand bit[1:0] y;
	cosntraint xy_c {
		(x==0) -> (y==0);
		solve x before y;
	}
endclass

sovle x before y约束的解

xy概率xy概率
001/2101/8
010111/8
020121/8
030131/8
sovle y before x约束的解
xy概率xy概率
001/8101/8
010111/4
020121/4
030131/4

tips:当修饰符为randc时,不要使用sovle…before…,因为randc默认最先计算,使用sovle…before…可能会带来未知错误。

### SystemVerilog 中的约束覆盖 在SystemVerilog中,约束覆盖用于验证随机化的数据是否确实遵循了所设定的约束条件。通过收集覆盖率统计信息,可以确保测试用例充分地探索了设计空间中的各种情况。 #### 约束覆盖的作用 当定义了一个复杂的约束集之后,可能难以直观判断这些约束是否被合理应用到了实际运行当中。因此,在仿真工具的支持下,可以通过启用约束覆盖功能来自动记录哪些合法组合已经被访问过以及它们发生的频率[^1]。 #### 实现方式 为了实现这一点,通常会在类声明部分加入covergroup结构体,并指定要监控的目标变量及其对应的bin范围;也可以利用`constraint_mode()`方法动态控制某些特定条件下才激活某组约束从而影响最终得到的结果分布模式[^2]。 下面给出一段简单的代码片段展示如何设置并使用带有覆盖分析特性的约束: ```systemverilog class packet; rand bit [7:0] addr; // 地址字段 rand bit [7:0] data; // 数据字段 covergroup cg_addr_data with function sample(bit [7:0] a,bit [7:0] d); ADDR : coverpoint a { bins low = {[0:$]}; bins high = {[$:255]}; } DATA : coverpoint d { bins small={0}; bins medium={[1:127]}; bins large ={[128:255]}; } cross ADDR ,DATA ; endgroup constraint c_valid{ (addr != 0)&&(data>0); // 自定义的有效性检查逻辑 } function new(); cg_addr_data=new(); endfunction task pre_randomize(); super.pre_randomize(); this.cg_addr_data.sample(this.addr,this.data); endtask endclass ``` 在此例子中,每当对象实例执行其内部预设好的随机化过程之前都会先调用一次`pre_randomize()`函数以更新当前样本点到相应的覆盖模型里去。这样做的好处是可以持续累积历史行为轨迹以便后续评估整个系统的健壮性和鲁棒性表现[^3]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值