SystemVerilog学习之路(3)— 定宽数组

SystemVerilog学习之路(3)— 定宽数组

一、前言

数组在数字验证当中是经常用到的,而且对于不同类型的数组其适用的应用场景也各不相同。

二、数组声明

在Verilog中对于数组的声明必须给出数组的上下界,但是在SystemVerilog中因为几乎所有数组都使用0作为索引下界,所以可以和C语言一样只给出数组宽度的便携式声明方式,如下为两种声明方式:

int lo_hi[0:15];	// 16个int类型整数[0]...[15]
int c_style[16];	// 16个int类型整数[0]...[15]

然后还可以通过在变量名后面指定维度的方式来创建多维的数组,当维度声明在变量名的右边时,靠右的为低维度,靠左的为为高维度;如下所示两个二位数组都是8行4列的,第1维度(低维度)为4个元素,第2维度(高维度)为8个元素,然后通过其对应的维度设置对应的元素,这和C语言中是一样的。

int array2[0:7][0:3];	// 完整的声明
int array3[8][4];		// 紧凑的声明
array2[7][3] = 1;		// 设置最后一个元素

另外我们需要知道的是,在很多的SystemVerilog仿真器中,存放数组元素是使用32bit的字边界(WOED),所以byte,shortint和int都是存放在一个字中,而longint则存放到2个字中。

三、初始化和赋值

在对数组初始化时,使用一个单引号加大括号来初始化数组,可以一次性地为数组的部分或所有元素赋值。如下所示,可以在大括号前标上重复次数来对多个元素重复赋值,还可以为那些没有显示赋值的元素指定一个缺省值。

int ascend[4] = '{0, 1, 2, 3};	// 对4个元素进行初始化
int descend[5];					// 声明5个元素的数组
descend = `{4, 3, 2, 1, 0};		// 为5个元素赋值
descend[0:2] = '{5, 6, 7};		// 为前3个元素赋值
ascend = '{4{8}};				// 四个值全部赋为8
descend = '{9, 8, default:1};	// 指定缺省值,{9, 8, 1, 1, 1}

四、合并数组

合并数组既可以用作数组,也可以当成单独的数据,即可以把它作为一个整体来访问,也可以把他分解成小的单元,合并数组的存放方式是连续的比特合集,中间没有任何的闲置空间。
在外面声明合并数组时,合并的位和数组大小作为数据类型的 一部分必须在变量名的前面指定,数组大小定义的格式必须是[msb:lsb],而不能是[size]。编写代码如下所示,变量bytes是一个有4个字节的合并数组,使用单独的32比特的1个字来存放,我们对其赋值一个32位的数据,然后$displayh()函数(默认输出十六进制)将其打印出来,另外我们使用两个,做分隔是为了插入一个空格,避免所有打印连在一起,

module array;
	initial begin
		bit[3:0][7:0]bytes;			// 四个字节组装成32比特
		bytes = 32'hcafe_dada;
		$displayh(bytes,,			// 显示所有的32比特
				bytes[3],,			// 显示最高字节
				bytes[3][7]);		// 显示最高bit位
	end
endmodule

仿真结果如下所示
在这里插入图片描述

五、非合并数组

当我们将数组大小写在了变量名右边时,即成为了非合并数组,在非合并数组中,字的低位用来存放数据,高位则不使用,如下所示,数组b_unpack被存放到三个字的空间里,
在这里插入图片描述
仿真器通常是使用两个或两个以上连续的字来存放logic和integer等四状态类型,这就会比存放双状态变量多占用一倍的空间。如下所示,我们使用logic类型来存储24bit的数据,变量声明如下,他们实际占据的实际存储空间应为2WORD3WORD,因为logic为四值逻辑类型,使用其每一位都需要两个bit来存储(0,1,x,z),所以l_pack需要连续的48bit来存储,则需要占据2WORD,而对于l_unpack来说,其第一维为8位的合并数组,则需要占据16bit存储空间,使用1WORD即可,然后第二维有3个元素,则总共需要3WORD

logic [3][7:0] l_pack;
logic [7:0]l_unpack[3];

六、数组操作

使用forforeach循环可以遍历整个数组,编写代码如下所示,声明i为for循环内的局部变量,通过$size函数返回数组的宽度,这样就可以遍历整个数组并对其初始化;在foreach循环中,只需要指定数组名并在其后面的方括号中给出索引变量,SystemVerilog便会自动遍历数组中的元素,索引变量将自动声明,并只在循环内有效。

module arr;
	initial begin
		bit [31:0]src[5],dst[5];
		for(int i=0;i<$size(src);i++)
			src[i] = i;
		foreach(dst[j])
			dst[j] = src[j]*2;			// dst的值是src的两倍
		foreach(src[j])
			$display("@1: src[%1d] = 'h%h", j, src[j]);
		foreach(src[j])
			$display("@2: dst[%1d] = 'h%h", j, dst[j]);
	end
endmodule

仿真运行如下所示
在这里插入图片描述
一般来说我们会使用foreach循环来更简单的遍历数组,但是对多维数组使用foreach时并不是像[i][j]这样把每个下标分别放在不同的方括号里,而是用逗号隔开后放在同一个方括号里[i, j],如下所示,使用foreach来遍历多维数组,

module arr;
	int md[2][3] = '{'{0,1,2}, '{3,4,5}};
	initial begin
		$display("Initial value:");
		foreach(md[i, j])
			$display("@1: md[%0d][%0d] = %h", i, j, md[i][j]);

		$display("New value:");
		md = '{'{9,8,7}, '{3{32'd5}}};	// 重新赋值
		foreach(md[i, j])
			$display("@1: md[%0d][%0d] = %h", i, j, md[i][j]);
	end
endmodule

仿真运行如下所示
在这里插入图片描述

七、复制和比较

对于数组的赋值,可以利用赋值符号=直接进行数组的复制;
对于数组的比较,可以在不使用循环的情况下,利用==!=来对数组进行聚合比较,不过比较只限于内容相同或不相同。编写代码如下所示

module arr;
	initial begin
		bit [31:0]src[5] = '{0, 1, 2, 3, 4},
				  dst[5] = '{5, 4, 3, 2, 1};
		if(src == dst)		// 两个数组的聚合比较
			$display("@1: src == dst");
		else
			$display("@1: src != dst");

		dst = src;			// 把src所有元素复制给dst
		src[0] = 5;			// 改变一个元素的值
		// 判断所有元素的值是否相等
		$display("@2: src %s dst", (src==dst) ? "==" : "!=");
		// 使用数组片段对第1-4个元素进行比较
		$display("@3: src[1:4] %s dst[1:4]", (src[1:4]==dst[1:4]) ? "==" : "!=");
	end
endmodule

仿真运行结果如下所示
在这里插入图片描述

八、附录

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值