zl程序教程

您现在的位置是:首页 >  工具

当前栏目

SystemVerilog学习-05-数组

学习数组 05 SystemVerilog
2023-09-14 09:13:04 时间

非组合型

对于Verilog,数组经常会被用来做数据存储,

reg [15:0] RAM [0 : 4095] ; //memory array

SV将Verilog这种声明数组的方式称之为非组合型声明,数组中的成员之间存储数据都是互相独立的。Sv保留了非组合型的数组声明方式,拓展了允许的类型。包括event,logic,bit,byte,int,longint,shortreal和real类型。

SV也保留了Verilog索引非组合型数组或者数组片段的能力,这种方式为数组以及数组片段的拷贝带来了方便。

声明数组的方式,以下两种皆可

logic [31:0] data [1024];
logic [31:0] data [0 :1023];

组合型

sv将verilog的向量作为组合类型数组声明方式。

wire [3:0] select;// 4-bit "packed array"

SV也进—步允许多维组合型数组的声明。

wire [ 3:0 ][ 7:0 ] data;//packed array

image-20211117085129451

也可以用来定义结构体的存储方式。

typedef struct packed {
logic [ 7:0]crc;
logic [ 63:0]data;
}data word;
data word [7:0] darray; // 1-D packed array

添加packed可以实现连续存放。组合型的数组和其数组片段可以用来拷贝和赋值。

初始化

组合型的数组的初始化,同向量初始化一致;

logic [3:0][7:0] a = 32'h0;
logic [3:0][7:0] b = {16'hz,16'h0}; 
logic [3:0][7:0] c = {16{2'b01} };

非组合型数组初始化时,需要通过‘{}对数组每个维度进行赋值。

int d [0:1][0:3] = '{'{7,3,0,5}, '{ 2,0,1,6}};

赋值

非组合型数组在初始化时,也可以类似结构体初始化,可以通过’{}和default关键字进行初始化。

非组合型数组的数据成员或者数组本身均可以为其赋值:

byte a [o:3][0:3];
a[1][0]= 8' h5;// assign to one element

以下是组合型数组的赋值方法:

image-20211117091849642

拷贝

对于组合型数组,由于数组会被视为向量,因此当赋值左右两侧操作时大小为度不一致时,也可以做赋值。如果当尺寸不相同时,则会通过截取或者扩展右侧操作数的方式来对左侧操作数赋值。

非组合数组,发生数组间拷贝时,要求左右两侧操作数维度和大小必须严格一致。对于非组合数组无法直接赋值给组合型数组,组合型数组也无法直接赋值给非组合数组。

foreach

sv添加foreach循环来对一位或者多位数组进行循环索引,而不需要指定该数组的维度大小。foreach循环结构中的变量无需声明,变量时只读的,作用域只在此循环结构中。

int sum [1:8][1:3] ;
foreach (sum[i,j])
sum[i][j]= i +j;//initialize array

系统函数

sv中提供一些系统函数方便对数组进行操作。

  • $dimensions(array_name):用来返回数组的维度。
  • l e f t ( a r r a y n a m e , d i m e n s i o n ) : 返 回 指 定 维 度 的 最 左 索 引 值 ( m s b ) 。 类 似 的 , 还 有 left(array_name, dimension):返回指定维度的最左索引值(msb)。类似的,还有 left(arrayname,dimension)(msb){right, low, high}(array_name, dimension)。
  • $size(array_name, dimension):可以返回指定维度的尺寸大小。
  • $increment(array_name, dimension):如果指定维度的最左索引值大于或等于最右索引值,那么返回1,否则返回-1。
  • $bits(expression):可以用来返回数组存储的比特数。

动态数组

动态数组是个非组合数组。

SystemVerilog 提供了动态数组类型,可以在仿真时分配空间或调整宽度,这样在仿真中就可以使用最小的存储量。动态数组在声明时使用空的下标[]。这意味着数组的宽度不在编译时给出,而在程序运行时再指定。

数组在最开始时是空的,所以你必须调用new[]操作符来分配空间,同时在方括号中传递数组宽度。可以把数组名传给new[]构造符,并把已有数组的值复制到新数组里。

int dyn[],d2[];  //声明动态数组
initial begin
	dyn=new[5];//分配5个元素
	foreach (dyn[j]) dyn[j]=j;//对元素进行初始化
	d2= dyn; //复制一个动态数组
	d2[o]=5; //修改复制值
end

内建方法size()可以返回动态数组的大小。内建方法delete()可以清空动态数组,使其尺寸变为0。动态数组在声明时也可以完成其初始化

队列

SystemVerilog引进了一种新的数据类型—队列,它结合了链表和数组的优点。队列与链表相似,可以在一个队列中的任何地方增加或删除元素,这类操作在性能上的损失比动态数组小得多,因为动态数组需要分配新的数组并复制所有元素的值。队列与数组相似,可以通过索引实现对任元素的访问,而不需要像链表那样去遍历目标元素之前的所有元素。

队列是个组合数组。sv引入了队列类型,它结合了数组和链表的特点。可以在队列的任何位置添加或者删除数据成员。可以通过索引来访问队列的任何一个成员。通过[ ] 来 声 明 队 列 , 队 列 的 索 引 值 从 0 到 ]来声明队列,队列的索引值从0到 ]0

可以通过内建方法push_back(val)、push_front(val)、pop_back()和pop_front()来顺序添加或者移除并且获得数据成员。insert(pos, val)来在指定位置插入数据成员。delete()来删除所有数据成员。

关联数组

如果想要在仿真时创建一个大的数组,也许动态数组是一个选择,不过有的时候,我们并不需要那么大的一个数组。由于处理器在访问存储时的访问的随机或者散乱的,这意味在一个测试中,处理器也许只会访问几百个存储地址,而剩下大多数的地址都将被初始化为0并且浪费了仿真时的存储空间。

关联数组可以用来存放散列的数据成员。类似python的字典。散列的索引类型除了为整形以外还可以为字符串或者其它类型,而散列存储的数据成员也可以为任意类型。

不定长的能用内建方法size()。

数组操作

缩减方法

基本的数组缩减方法是把一个数组缩减成一个值。最常用的缩减方法是sum,它对数组中的所有元素求和。其它的数组缩减方法还有product(积),and(与),or(或)和xor(异或)。

定位方法

对于非合并数组,可以使用数组定位方法,其返回值将是一个队列而非一个数据成员。使用foreach也可以实现数组的搜索,不过使用find…with则在查找满足条件的数据成员时,更为方便。

image-20211117100250002

排序方法

可以通过排序方法改变数组中元素的顺序,可以对它们进行正向、逆向或者乱序的排列。

image-20211117100411631

References

  1. 路科验证西电课程PPT
  2. 《SystemVerilog验证-测试平台编写指南》