目录
1 定宽数组
1.1 一维定宽数组
1.2 多维定宽数组
1.3 packed合并数组
1.4 unpacked非合并数组
1.5 混合数组
1.6 foreach循环结构
2 动态数组
3. 关联数组
4.队列queue
5.枚举enum
6.字符串string
7.结构体struct
1 定宽数组
1.1 一维定宽数组
int b[2:0] ; //一维定宽数组声明
int b[3]; //同上,声明简写
b='{0,1,2}; //赋值
1.2 多维定宽数组
int array[1:0][2:0]; //unpacked数组,多维数组,表示2行3列
int array[2][3]; //声明同上,简写
array[2][3]='{'{0,1,2},'{3,4,5}}; //赋值方法
array[2][3] //设置最后一个元素
1.3 packed合并数组
相当于一个只有一个元素的数组,合并型数组可以实现连续的存储,赋值时不需要用 '{ }
bit [3:0][7:0] b_pack; //合并数组;4个8bit数据
b_pack = 32'haabb_ccdd; //合并数组进行赋值
$display("%h",b_pack); //合并数组打印
$display("%h",b_pack[3]); //打印最高位,即8'haa
1.4 unpacked非合并数组
unpacked数组存储是不连续的,赋值时需要用'{ }
bit [7:0] b_unpack[3]; //该数组有3个元素,每个元素8bits,3行8列
- 非合并数组浪费空间,合并数组节省空间
- 非合并数组>=1个元素,合并数组只有一个元素
- 非合并数组命名左右两侧都有,合并数组在数组名的左边
1.5 混合数组
program test;
bit [3:0][7:0] array[0:2];
initial begin
array[0]=32'haabbccdd;
array[1]=32'haabbccdd;
array[2]=32'haabbccdd;
$display("array[0]=%0h",array[0]);
$display("array[1][2]=%0h",array[1][2]);
$display("array[1][2][3]=%0h",array[1][2][3]);
end
endprogram
打印结果:
array[0]=aabbccdd
array[1][2]=bb
array[1][2][3]=1
1.6 foreach循环结构
SV添加foreach循环来对一维或者多维数组进行循环索引,不需要指定该数组的维度大小;
一维数组遍历:
initial begin
bit [31:0] src[5], dst[5];
for (int i=0;i<$size(src);i++) //for就是正常的for循环
src[i] = i;
foreach (dst[j])
dst[j] = src[j]*2; //foreach自动遍历数组中的所有元素
end
多维数组遍历:
int md[2][3] = '{'{0,1,2},'{3,4,5}};
//foreach对多维的遍历并不是写成md[i][j],而是写在一个方括号里,用逗号隔开
initial begin
$display("initial value:");
foreach (md[i,j])
$display("md[%0d][%0d] = %0d",i,j,md[i][j])
$display("new value:");
// 对最后三个元素赋值5
md = '{'{9,8,7},'{3{32'd5}}};
foreach (md[i,j])
$display("md[%0d][%0d]=%0d",i,j,md[i][j]);
end
- Foreach 循环结构中的变量无需声明;
- Foreach 循环结构中的变量是只读的,作用域只在此循环结构中
2 动态数组
定宽数组在编译已经确定大小,使用定宽数组可能会浪费空间,因此SV引入了动态数组,可以在仿真时声明空间,避免了浪费。
- SV提供了可以重新确定大小的动态数组,数据创建
- 动态数组声明用 [ ],使用 new[ ] 来分配空间
- 动态数组一开始的元素个数为空,非连续性,赋值需要使用'{ }
int dyn[],d2[]; //声明动态数组
initial begin
dyn = new[5] //分配5个元素
foreach (dyn[j]) dyn[j] = j ; //给元素赋值
d2 = dyn; // 复制一个动态数组
d2[0] = 5;
$display(dyn[0],d2[0]);
dyn = new[20](dyn);
dyn = new[100]
dyn.delete();
end
3. 关联数组
针对超大容量的数组,假如正在对一个有着几个G字节寻址范围的处理器进行建模,在典型的测试中,这个处理器可能只访问了用来存放可执行代码和数据的几百或几千个字节,这种情况下对几个G字节的存储空间进行分配和初始化显然是浪费的。
- 对于超大容量的数组,可以使用SV提供的关联数组类型,保存稀疏矩阵的元素,即只为实际写入的元素分配空间;
- 内存建模
数组方法
方法 | 示例 |
数组求和 | array.sum() |
数组求积 | array.product() |
数组求与 | array.and() |
数组求或 | array.or() |
数组找最大值 | min = array.max() |
数组找唯一值 | unique = array.unique() |
数组反序 | array.reverse() |
数组从低到高排序 | array.sort() |
数组元素随机 | array.shuffle() |
删除所有元素:
- A. detele
- A=new ( )
- A= '{ }
4.队列queue
声明队列时使用符号 [$] ,队列的元素都是连续赋值的,因此使用 { }
int q[$]={0,2,5}; //声明并赋值
q.insert(1,j); //在 2 前面插入 1 ;结果为:{0,1,2,5} ;也可以插入一个队列
q.push_front(1); //在队列前面插入一个1;结果为: {1,0,1,2,5}
q.pop_front(); //从队列头部取出1;结果为:{0,1,2,5}
q.delete(); //队列删除
队列的特点:数据管理
- 可以在队列任何位置添加和删除数据成员;
- 可以通过索引访问队列的任何一个成员;
- 队列的两端存取数据速度很快,但是在队列中间增删数据时就很耗时,因为需要对已经存在的数据进行搬移以便腾出空间
- 可以通过内建方法push_back()、push_front()、pop_back()和pop_front()来顺序添加或者移除数据;
- 通过 insert(val,pos) 在指定位置插入数据;
- 通过delete()删除所有数据成员;
5.枚举enum
意义:提高了代码的可读性,常和typedef搭配使用。
- 规范的操作码和指令例如ADD、WRITE、IDLE等有利于代码的编写和维护,它比直接使用'h01这样的常量使用起来可读性和可维护性更好。
- 枚举类型enum经常和typedef搭配使用,由此便于用户自定义枚举类型的共享使用。
6.字符串string
- 声明字符串:string + 字符串名
- 格式化字符串:$sformmatf( )
- 打印字符串:$display()
7.结构体struct
- 在SV中可以使用struct语句创建结构,跟c语言类似。
- 不过struct的功能少,它只是一个数据的集合,伴随typedef可以用来创建新的类型,并利用新类型来声明更多变量。
- 结构体为非连续,赋值时需要使用 '{ }
//为了共享该类型,通过typedef来创建新类型
typedef struct {bit [7:0] r,g,b;} pixel_s; //定义一个类型,名字为pixel_s
pixel_s my_pixel; //声明一个变量
my_pixel = `{`h10,`h10,`h10}; //结构体类型的赋值