数组是元素的集合,所有元素都具有相同的类型,并使用其名称和一个或多个索引进行访问。 Verilog 2001 要求数组的下限和上限必须是数组声明的一部分。 System Verilog 引入了紧凑数组声明样式,只需给出数组大小以及数组名称声明就足够了。
下图显示了 System Verilog 中使用的不同类型的数组。
数组类型一览表列表:
数组类型 | 描述 |
---|---|
压缩数组(Packed Array) | 先声明数组名称,后声明数组维度 |
非压缩数组(Unpacked Array) | 先声明数组维度,后声明数组名称 |
动态数组(Dynamic Array) | 内存将在运行时分配 |
关联数组(Associative Array) | 仅在使用时分配内存并且使用任何索引类型对数组进行索引 |
队列(Queue) | 它类似于 fifo,我们可以在运行时向队列添加和删除元素 |
数组的函数 | 它由数组定位函数、数组排序函数和数组缩减函数组成 |
静态数组#
在固定大小数组/静态数组中,数组大小在整个模拟过程中将保持不变,一旦声明数组就无需创建它。默认情况下,数组将初始化为值“0”。在这种类型的数组中,内存将在编译阶段被占用,并且我们无法在运行时重新分配内存。
静态数组有两种类型
- 压缩数组
- 非压缩数组.
压缩数组#
压缩数组(Packed Arrays)是一种在数组名称之前声明数组维度的数组。在此数组中的多个位存储在一个内存位置中。
注意: 它可以由任何单个位数据类型 bit、logic 和 reg 组成。我们不能对压缩数组使用多位数据类型。
语法: [data_type] [dimensions] [array_name];
示例:
1) bit [3:0]abc = 4'b0110
2) logic [15:0]pqr = 16'h10fe
3) reg [7:0]xyz = 8'd16
一些注意事项:
- 如果压缩数组被声明为带符号的,则被视为单个向量的数组应被带符号。数组的各个元素都是无符号的,除非它们是声明为有符号的命名类型。
- 压缩数组的最大大小可以受到限制,但至少应为 65536 (2^16) 位。
- 压缩数组是可综合的。
下图展示了二维压缩数组中数组元素的存储方式。对于位 [2:0][3:0]xyz 示例,数组元素从左到右将占用内存。
压缩数组的应用:
它们用于存储可以执行位选择和部分选择操作的数据包结构。
非压缩数组#
非压缩数组(Unpacked Arrays)是在数组名称之后声明数组维度的数组。在此,多个位将存储在不同的存储位置中。
语法: [data_type] [array_name] [dimension];
示例:
byte a[8] = '{4,5,6,2,3,7,9,10}
int abc[10] = $urandom_range(10,50);
其中,$urandom_range是内置函数,它生成10到50之间的随机数。
一些注意事项:
- 它们可以是任何数据类型。
- 如果非压缩数组被声明为有符号,则这适用于数组的各个元素,因为整个数组不能被视为单个向量。
- 非压缩数组可以以模拟器选择的任何方式排列在内存中——不必是连续的。
- 它们可以是固定大小的数组、动态数组、关联数组或队列。
- 非压缩数组是不可综合的。
下图显示了数组元素如何存储在二维非压缩数组中。对于 int abc[2][3] 示例,数组元素从左到右将占用内存。
非压缩数组的应用:
它们用于对随机存取存储器 (RAM)、只读存储器 (ROM) 和一次访问一个元素的寄存器文件进行建模。
混合多维数组#
压缩数组和非压缩数组的混合称为混合多维数组。
语法: [data_type] [dimensions] [array_name] [dimensions];
示例:
logic [2:0][3:0] mixed_array [2:0][3:0];
一些注意事项:
- 首先按从最左边到最右边的顺序引用所有非压缩数组
- 然后按从最左边到最右边的顺序引用所有压缩数组。
在给定的示例中,将从左到右分配内存,并且对于第一个非压缩数组维度将被考虑,如下图所示,然后考虑压缩数组维度。
动态数组#
动态数组(Dynamic Arrays)是非压缩的数组,其大小可以在运行时设置或更改。动态数组的空间在运行时显式创建之前并不存在。
语法: <data_type> array_name []
示例:
int abc[] = new[7];
abc[7] = '{11,12,13,14,15,16,17};
一些注意事项:
- 未初始化的动态数组的默认大小为 0。
- 动态数组支持所有变量数据类型作为元素类型,包括数组。
- 动态数组中的越界访问会指向数据类型的默认值。
动态数组函数一览表
函数 | 示例 | 描述 |
---|---|---|
构造函数: new [value] | abc.new[] | 设置动态数组的大小并初始化其元素或在运行时更改数组的大小。如果该值为零,则数组将变为空。如果该值为负数,则表示错误。 |
函数: int size() | abc.size() | size() 方法返回动态数组的当前大小,如果数组尚未创建,则返回零 |
函数: void delete() | abc.delete() | delete() 方法清空数组,导致数组大小为零 |
动态数组的应用:
可以在模拟期间分配和重新调整大小的动态数组将避免这种不必要的内存分配。
关联数组#
关联数组(Associative Arrays)是一种非压缩数组数据类型。它在使用之前不会分配任何存储空间,并且用于访问元素的索引类型不限于整数。
语法: <data_type> array_name [index_type]
其中,索引类型是任何数据类型或其通配符“*”。
示例:
int abc[*];
abc = '{ 1:20, 25:22, 38:66};
string pqr[string];
pqr = '{"fruits":"mango" , "vegetables":"cucumber" , "season":"monsoon"};
一些注意事项:
- 关联数组的元素都是非压缩的。
- 模拟器可以将其存储为哈希(查找)表,以便极快地访问其元素。哈希表包含一组元素的数组。称为哈希函数的函数生成一个唯一键来计算该数组的索引,从中获得正确的数组元素值。
- 关联数组中的元素的访问方式与一维数组中的元素类似。
- 如果尝试读取无效(不存在)的关联数组条目,则模拟器将发出警告,并为 4 状态整数类型返回值“x”,或为 2-状态整数类型返回值“0”。状态积分类型。
- 使用“*”这个通配符会增加模拟时间,因此在声明数组时避免使用它。
关联数组方法一览表:
函数 | 示例 | 描述 |
---|---|---|
int num () | abc.num() | 返回关联数组中的条目数 |
int size () | abc.size() | 返回条目数,如果为空则返回0 |
void delete ([input index]) | abc.delete(index) | 指定索引时,将删除该索引处的条目,否则将删除整个数组 |
int exists (input index) | abc.exists(index) | 检查指定索引处是否存在元素;如果存在则返回 1,否则返回 0 |
int first (ref index) | abc.first(index) | 将第一个索引的值分配给给定的索引变量;对于空数组返回 0 |
int last (ref index) | abc.last(index) | 将最后一个索引的值分配给给定的索引变量;对于空数组返回 0 |
int next (ref index) | abc.next(index) | 查找值大于给定索引的最小索引 |
int prev (ref index) | abc.prev(index) | 查找值小于给定索引的最大索引 |
关联数组的应用:
用于设计内容可寻址存储器 (CAM) 的关联数组。用于验证存储器的随机读取或写入测试可以使用关联数组来仅存储已写入地址的数据。这将比 Verilog 中通常使用的整个数组占用的内存少得多。
队列#
队列是一种数据类型,用于以未压缩数组格式存储相同数据类型的可变大小有序集合,用于在数组两端插入元素和删除数组中的元素。它就像缓冲区一样,用于模拟先进先出(FIFO)和后进先出(LIFO)。
语法: data_type name[$];
data_type - 队列元素的数据类型 name - 队列名称 [$] - 声明无界队列
队列有两种类型
有界队列#
队列有大小限制。我们需要在声明队列时提供最大值。
语法: data_type name[$:255];
这里 $ 是第一个成员,255 是最后一个成员
无界队列#
队列没有大小限制。我们不提供队列的大小,它是可变大小的队列。
语法: data_type name[$];
这里 0 是第一个成员,$ 是最后一个成员
队列的函数#
队列的函数一览表
函数 | 示例 | 描述 |
---|---|---|
function int size (); | queue1.size(); | 返回队列中的项目数 |
function void insert (input integer index, input element_t item); | queue1.insert(int 0, 2); | 在指定索引位置插入给定项目 |
function void delete ( [input integer index] ); | queue1.delete(0); | 删除指定索引位置的项目 |
function element_t push_front (input element_t item); | queue1.push_front(“yelahanka”); | 将给定元素插入队列的前面 |
function element_t push_back (input element_t item); | queue1.push_back(“udupi”); | 将给定元素插入到队列末尾 |
function void pop_front (); | queue1.pop_front() | 删除并返回队列的第一个元素 |
function void pop_back (); | queue1.pop_back() | 删除并返回队列的最后一个元素 |
数组的优点和缺点:#
数组类型 | 优点 | 缺点 |
---|---|---|
固定大小的数组 | 1) 可以在运行时之前预先计算大小。 2) 内存在内存 bss 部分的 ROM 中分配,与非压缩数组相比,模拟时间更少。 | 1) 大小是固定的,我们无法扩展数组。 2) 内存浪费 |
动态数组 | 1) 连续内存分配 2) 我们可以使用循环从一个内存位置跳转到另一个内存位置。 3) 由于有序,我们可以轻松地在数组中移动 4) 与队列相比,执行时间更短 | 1) 我们无法在特定索引位置插入和删除值 2) 内存分配在堆内存中,因此与固定数组相比,模拟时间更长 |
关联数组 | 1) 内存友好 2) 任何数据类型都可用于索引 3) 我们可以在特定索引处插入和删除值 | 1) 内存分配不连续 2) 索引之间没有固定关系,因此遍历数组很困难 3) 跳转到数组中其他内存位置需要索引号或者键 |
队列 | 1) 我们可以插入和删除特定索引处的值 2) 我们可以在现有元素之间插入元素 3) 海量数据可轻松高效管理 4) 推入和弹出操作可以轻松执行,比关联数组更好 | 1) 与动态数组相比,执行时间更长 2) 与动态数组相比,它有点复杂,因为它会扩展/增加 |
数组的函数#
在 System Verilog 中,数组操作方法是用于搜索和排序的内置方法。数组操作方法迭代每个数组元素以计算 with 子句给出的表达式。对于某些方法来说,with 子句是必须的,而对于某些方法来说,with 子句是可选的。 “with”是指对现有数组进行条件评估。下图是数组操作方法的流程图
数组操作函数一览表
**非破坏性:**其输出存储在另一个数组中的数组不会影响原始数组
函数 | 示例 | 描述 |
---|---|---|
find() with condition(); | array.find(check) with (check >=“oldtown”) | 返回满足给定表达式的所有元素 |
find_index() with condition(); | array.find_index(check) with (check ==“yelahanka”); | 返回满足给定表达式的所有元素的索引 |
find_first() with condition(); | array.find_first(check) with (check < “yelahanka” & check >= “newton” ); | 返回满足给定表达式的第一个元素 |
find_first_index() with condition(); | array.find_first_index(check) with (check < “yelahanka”); | 返回满足给定表达式的第一个元素的索引 |
find_last() with condition(); | array.find_last(check) with (check < “oldtown”); | 返回满足给定表达式的最后一个元素 |
find_last_index() with condition(); | array.find_last_index(check) with (check < “oldtown”); | 返回满足给定表达式的最后一个元素的索引 |
function max(); | array.max(); | 返回值为最大值的元素 |
function min(); | array.min(); | 返回值为最小值的元素 |
function unique(); | array.unique(); | 返回作为唯一值的所有元素 |
function unique_index(); | array.unique_index(); | 返回作为唯一值的所有索引位置 |
function sum(); | array.sum(); | 返回所有元素的总和 |
function product(); | array.product(); | 回所有元素的乘积 |
function and(); | array.and(); | 回所有元素的按位与(&) |
function or(); | array.or(); | 返回数组中所有元素的按位或 |
function xor(); | array.xor(); | 返回数组中所有元素的按位 XOR(^) |
**破坏性:**其输出直接影响原始数组的数组
函数 | 示例 | 描述 |
---|---|---|
function reverse(); | array.reverse(); | 反转数组元素的顺序 |
function sort(); | array.sort(); | 升序对数组元素进行排序 |
function rsort(); | array.rsort(); | 按降序对数组元素进行排序 |
function shuffle(); | array.shuffle(); | 对数组元素进行混洗,使索引值按随机顺序排列 |