非组合型
对于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
也可以用来定义结构体的存储方式。
typedef struct packed { logic [ 7:0]crc; logic [ 63:0]data; }data word; data word [7:0] darray; // 1-D packed array
非组合型数组初始化时,需要通过‘{}
对数组每个维度进行赋值。
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
以下是组合型数组的赋值方法:
拷贝
对于组合型数组,由于数组会被视为向量,因此当赋值左右两侧操作时大小为度不一致时,也可以做赋值。如果当尺寸不相同时,则会通过截取或者扩展右侧操作数的方式来对左侧操作数赋值。
非组合数组,发生数组间拷贝时,要求左右两侧操作数维度和大小必须严格一致。对于非组合数组无法直接赋值给组合型数组,组合型数组也无法直接赋值给非组合数组。
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):用来返回数组的维度。
- 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则在查找满足条件的数据成员时,更为方便。
排序方法
可以通过排序方法改变数组中元素的顺序,可以对它们进行正向、逆向或者乱序的排列。
References
- 路科验证西电课程PPT
- 《SystemVerilog验证-测试平台编写指南》