动态数组、关联数组、队列——SV,SystemVerilog

动态数组、关联数组、队列——SV,SystemVerilog1.定宽数组声明:intlo[0:15];intlo[16];//16个整数[0]…[15]intarr[0:7][0:3];//等效与intarr[8][4];8行4列的数组arr[8][4]=1;//设置数组的最后一个元素为1知识1–for和foreach的使用对于f[0:4


👉合并数组与非合并数组可以看:合并与非合并数组

一、定宽数组

1.1 声明

  • 写在数组名左边的是表示在同一行的数据 ,在同一行是连续的,所以这一部分要用 { }赋值;
  • 写在数组名右边的是表示在不同行的数据,在不同行是不连续的,所以这一部分要用’{ }赋值;

如下:

int lo [0:15]; //表示有16行,每一行有1个int类型的数据 
int lo [16];  //与上面意义相对,表示16个int类型的整数

int arr_unpacked[0:7] [0:3]; // 表示有8行,这8行中的每一行有4个数据,每个数据都是一个int类型的
arr_unpacked[8] [4]=1;// 设置数组中的的最后一个元素为1 

int [3] [2] arr_packed;//表示在同一行中,有三个数组,每个数组内有2个int类型的数据
arr_packed[0] = { 
   2,4};//给这一行中第1个数组赋值
arr_packed[2][1] = 5;//给这一行中第3个数组中的第2个数值赋值

bit [3:0][7:0] arr_mix [2:0]; // [3:0][7:0] 表示一个32bit 的 合并数组,[2:0]表示有3 个32 bit的合并数组

想信从上面的例子大家已经明白,数组在进行赋值的时候,是根据索引值来确定要在数组中赋值的位置。为了明白一个数组中元素具体是如何分布和赋值的的,以一个非合并数组为例:

bit [31:0] src [5] = '{ 
   5,4,3{ 
   1}};//有5行,每一行又包括32个数据,每个数据是1个bit类型的
src[0] = 32'b101; //或者32'd5
src[1][1:0] =  32'b00; //因为'd4 = 'b 100
src[4][1] =  32'b1; 

1.2 for 和 foreach 遍历数组

for 和 foreach会按照数组中元素的索引值开始遍历。也就是说:

  • 对于 f[0:4] 数组,遍历索引值从 0 ~ 4,采样foreach(f[i]),等同于for( int i = 0; i <= 4; i ++)

  • 对于 f[6:2] 数组,遍历索引值从 6 ~ 2,foreach(f[i]),等同于for( int i = 6; i <= 2; i –)

如下,对常量数组的遍历:

int array1 [3] = '{ 
   2,3,4}; 
foreach( array1[i] ) $display("array1[%0d] = %0d;",i,array1[i]);
/* 输出结果:array1[1] = 2; array1[1] = 3; array1[2] = 4; */

int array2 [2] [3] = '{'{ 
   2,3,4},'{ 
   4,5,6}}; 
//遍历方式一:
foreach( array2[i][j] ) $display("数组中第[%0d] [%0d]= %0d;",i,j,array1[i][j]);
//遍历方式二:
foreach(array[i]) begin 
  foreach(arrayy[,j])	$display("数组中第[%0d] [%0d]= %0d;",i,j,array1[i][j]);
end
/* 输出结果: [0][0] = 2 [0][1] = 3 [0][2] = 4 [1][0] = 4 [1][1] = 5 [1][2] = 6 */

1.3 数组的复制与比较

对于组合型,数组会被视为一个向量,即便两边的操作数的维度不相同时,也可以做赋值

  • 长的赋值给短的,会截断高位,保留跟短的相同长度的低位
  • 短的赋值给长的,短的会占据低位,高位会被填充为0

对于非组合型,要求左右两侧操作数的维度和大小必须一致;

非组合型无法直接赋值给组合型;同样组合型也无法直接赋值给非组合型
注:有关组合型和非组合型数组,见
合并数组与非合并数组

1.4 数组内建的方法

SV中内建的函数,可以直接用数组名调用,对数组进行操作。

函数名 描述
size( ) 返回当前数组的大小
delete( ) 删除数组内的所有元素

二、动态数组

定宽数组类型的宽度在编译时就被确定了,而动态数组可以认为是一个非合并数组,动态数组在声明时没有指定数组的大小,在对数组初始化时(调用new[ ])需要指定数组的大小,从而分配内存空间。

2.1 创建动态数组

动态数组的声明方式,如下,

//声明动态数组
bit [3:0] nibble[]; 
integer mem[2][]; 

//调用new[ ] 对动态数组初始化
nibble = new[5];// 5 * 4bit的数组
mem = new[5];   // 5 *2integer的数组

nibble = new[3];//将之前数组中的元素全部是否,重新初始化

注意

  • 使用new[ ]时,中括号中一定要传递数值;
  • 最后nibble内原来的值都不存在了,因为通过 nibble= new[3] 将原来的空间释放了;

2.2 给动态数组赋值

int idest[]; //声明动态数组
int isrc [3] = '{ 
   5, 6, 7}; // 常量数组
idest = new [3] (isrc); // 设置动态数组的大小为3,并赋值为(5, 6, 7)

注意:

  • 动态数组的声明和初始化可以直接用一条语句完成;
  • 在new[ ]中设置动态数组大小时,并不完全需要匹配所赋数组的大小。当初始化动态数组的大小较大时,赋值的常量数组会被截断以匹配;当它较小时,初始化的数组将使用默认值填充以获得指定的大小。如下:
int src[3] = '{ 
   2, 3, 4};;
int dest1[];
int dest2[];

dest1 = new[2] (src); // dest1中的元素为: {2, 3} ,数组被截断
dest2 = new[4] (src); // dest2中的元素为: {2, 3, 4, 0} ,用默认值0 补齐

注:数组填充时是按索引值来填充的,如’{2, 3, 4},2、 3、 4 的索引值分别为0、1、2 。

三、队列

队列有以下的特点:

  • 结合了链表和数组的优点,可以在任何地方添加或删除元素,并通过索引实现对任一元素的访问;
  • 队列不需要用new[ ]去创建内存空间,一开始其所占空间为0;
  • 队列中的元素是连续存储的,故不需要使用单引号 ’ { }方式赋值
  • 队列的两端存取数据速度很快,但是在队列中间增删数据时就很耗时,因为需要对已经存在的数据进行搬移以便腾出空间;
  • 队列自带方法 push_back() 和 pop_front() 的 结合来实现类似FIFO的功能;

3.1 声明

声明: [$] ,队列元素的标号从0 到 $ ;

int q[$]; //声明队列,队列中的数据类型为int类型
byte q1[$]; // 队列中的数据类型为byte类型
string names[$] = { 
    "Bob" }; // 队列中的数据类型为string类型

int q2[$] = { 
   0,2,5};   // 声明+初始化 
q2.insert(1,j);    //在 2 前面插入 1 ;结果为:{0,1,2,5} ;也可以插入一个队列
q2.push_front(1);   //在队列前面插入一个1;结果为: {1,,0,1,2,5} 
q2.pop_fron();	//从队列头部取出;结果为:{0,1,2,5} 
q2 = { 
   0,1,2,5,6};//在末尾插入一个6;结果为: {0,1,2,5,6}

3.2 队列内建的方法

可以直接使用队列名调用如下的方法。

方法 描述
function int size(); 返回当前队列中元素的个数
function void insert(input integer index, input element_t item); 在指定索引值位置处插入指定的值
delete( ) 删除队列内的所有元素
function element_t pop_front( ) 在队列的开头取出一个元素
function element_t pop_back( ) 在队列的末尾取出一个元素
push_front( input element_t item) 在队列的开头插入一个元素
push_back( input element_t item) 在队列的末尾插入一个元素

四、 关联数组

用来保存稀疏矩阵的元素,创建超大容量的数组。当对一个非常大的地址空间进行寻址时,systemverilog只为实际写入的元素分配空间,这样可以节省空间。

4.1 声明

关联数组很像一个hashmap,也就是可以看做由键值对组成,右边为索引的类型,左边为索引值的类型。

bit [63:0] assoc[bit[63:0]];//以64bit数据为索引,查找关联数组中的64 bit的数据
int age[string];//以字符串为索引,查找关联数组中的int类型数据
integer i_array[*];//未规定索引类型,通配

怎么给关联数组赋值呢?

int imem[int];
imem[ 2'b3 ] = 1; //索引为2'b3,索引值为1
imem[ 16'hffff ] = 2;//索引为16'hffff,索引值为2
imem[ 4b'1000 ] = 5;//索引为4b'1000 ,索引值为5
$display( "关联数组中有%0d 个键值对\n", imem.num );//3个

4.2 关联数组内建的方法

方法 描述
function int num(); 返回关联数组中存储的键值对数目,若为空则返回0
function int size(); 返回关联数组中存储的键值对数目,若为空则返回0

其他的方法可以参见IEEE_systemverilog手册的章节7.9 。

五、 选择存储类型

什么情况下使用常量数组、动态数组、关联数组、队列呢?从以下几个方面考虑:

5.1 使用灵活性

  • 索引是连续的非负整数,采用定宽或动态数组
  • 索引不规则,且稀疏分布,采用关联数组
  • 元素数目变化很大数组,采用队列

5.2 存取速度

  • 定宽和动态数组都是存放在连续的存储空间中,访问任何的元素时间都相同,与数组大小无关
  • 队列在收尾存取数据几乎没有任何开销,但是在队列中间插入或删除元素需要对其他元素进行搬移以腾出空间。在很长的队列中间插入新的元素,会需要很长的时间
  • 关联数组的存取速度是最慢的,因为过程中要有大量算法实现

5.3 排序方式

  • 如果元素一次性全部加入,选择定宽或者动态数组,只需要对数组进行一次分配
  • 如果元素一个一个加入,选择队列
  • 如果数组的值不连续且互异,可以使用关联数组,把元素值本身作为索引

5.4 占用系统的存储空间

  • 小于1000个元素的数组,各种类型对存储器用量影响不大
  • 1000 ~ 100万个元素的数组,定宽和动态数组具有最高的存储器使用效率
  • 大于100万个元素的数组,重新检查算法是否有问题
  • 对兆字节量级的存储器建模应该使用关联数组,但是注意指针带来的额外消耗,关联数组中每个元素站的空间可能会比定宽和动态数组大好几倍

今天的文章动态数组、关联数组、队列——SV,SystemVerilog分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/10192.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注