sv语言中压缩数组和非压缩数组
在 SystemVerilog (SV) 中,压缩数组(Packed Array)和非压缩数组(Unpacked Array)是两种不同的数组存储方式,主要区别体现在内存布局、访问方式和用途上。以下是详细对比:
1. 压缩数组(Packed Array)
- 内存布局:
- 连续存储,所有元素紧密排列在内存中,占用一个连续的位向量(bit vector)。
- 类似于 C 中的多比特变量(如
int
或bit[31:0]
)。 - 示例:
bit [3:0][7:0] packed_array;
占用 32 位(4×8),视为一个整体。
- 访问方式:
- 支持位选择和部分选择(如
packed_array[2][3]
)。 - 可直接用于位操作(如逻辑运算、移位等)。
- 支持位选择和部分选择(如
- 用途:
- 用于硬件信号建模(如寄存器、总线)。
- 适合需要位级操作的场景(如协议字段、状态编码)。
- 可综合为硬件中的连续信号。
- 特点:
- 维度写在变量名左侧(如
[msb:lsb]
)。 - 只能是静态数组(编译时确定大小)。
- 支持多维压缩(如
logic [2:0][1:0]
是 3×2 的压缩数组)。 - 如果一个数组被定义为有符号数, 那么其存储的所有压缩数组都被默认为有符号
数, 而每个压缩数组的成员是无符号数。 - 压缩数组被指定为任何网线类型或者标量变量类型 ( 如: reg、 logic 和 bit) 。 具有预定义宽度的整数类型不能声明成压缩数组, 这些类型包括: byte、 shortint、 int、 longint 以及 integer。 一个具有预定义宽度的整数类型可以被看作是一个一维的压缩数组。 这些整数类型的压缩尺寸应该以趋向 0 的方向编号, 并且最右边的索引是 0。 非压缩数组可以被指定为任何数据类型。
- 维度写在变量名左侧(如
2. 非压缩数组(Unpacked Array)
- 内存布局:
- 元素独立存储,不保证内存连续,可能分散或按编译器优化布局。
- 类似于 C 中的数组(如
int arr[10]
)。 - 示例:
int unpacked_array[4];
是 4 个独立的 32 位整数。
- 访问方式:
- 仅支持整体或索引访问(如
unpacked_array[1]
)。 - 不支持直接位操作(需先赋值给压缩数组)。
- 仅支持整体或索引访问(如
- 用途:
- 用于存储大量数据(如存储器、数据缓冲区)。
- 适合软件建模(如测试平台中的动态数据)。
- 可动态分配(如
unpacked_array = new[size]
)。
- 特点:
- 维度写在变量名右侧(如
[size]
或[start:end]
)。 - 可以是静态或动态数组。
- 支持复杂数据类型(如结构体、类对象)。
- 维度写在变量名右侧(如
举个例子
logic [3:0][7:0] packed; // 4字节压缩数组(32位连续)
logic [7:0] unpacked [0:3]; // 4个独立的8位非压缩数组
initial begin
packed = 32'hAABB_CCDD; // 直接赋值
unpacked[0] = 8'hAA; // 逐个元素赋值
$display("%h", packed[2]); // 输出 CC(位选择)
end
在实际使用条件下
(1) 合并数组
- 支持位选择和部分选择:
- 可直接访问任意位或子范围。
packed_arr[2] // 访问第 2 个 8 位元素(bits 16-23) packed_arr[1][3] // 访问第 1 个元素的第 3 位(bit 11)
- 支持位操作:
- 可直接用于逻辑运算、移位等。
assign packed_arr = (packed_arr << 4) | 8'hFF;
(2) 非合并数组
(2) 非合并数组
多维数组的区别
(1) 合并多维数组
(2) 非合并多维数组
5. 适用场景
(1) 合并数组的典型用途
(2) 非合并数组的典型用途
6. 混合使用示例
// 合并 + 非合并混合
logic [3:0][7:0] packed; // 4×8 位合并数组
logic [7:0] unpacked [0:3]; // 4 个 8 位非合并数组initial beginpacked = {8'hAA, 8'hBB, 8'hCC, 8'hDD}; // 合并数组整体赋值unpacked = '{8'h11, 8'h22, 8'h33, 8'h44}; // 非合并数组初始化// 合并数组支持位操作packed[2] = packed[1] << 1;// 非合并数组需逐元素操作unpacked[0] = unpacked[1] & 8'hF0;
end
- 仅支持索引访问:
- 必须通过完整索引访问元素,不支持直接位操作。
unpacked_arr[2] // 合法:访问第 2 个元素 unpacked_arr[1][3] // 合法:访问第 1 个元素的第 3 位 // unpacked_arr << 4; // 非法!非合并数组不能直接移位
- 位操作需转换:
若需位操作,需先赋值给合并数组。 赋值与初始化
(1) 合并数组
- 整体赋值:
- 可一次性赋值所有位。
packed_arr = 32'hAABB_CCDD; // 合法
- 部分赋值:
- 支持对子范围赋值。
packed_arr[1:0] = 16'h1234; // 合法
- 需逐个元素赋值:
- 不能直接整体赋值(除非使用
'{}
初始化)。
unpacked_arr = '{8'hAA, 8'hBB, 8'hCC, 8'hDD}; // SystemVerilog 2005+ 合法 // unpacked_arr = 32'hAABB_CCDD; // 非法!
- 不能直接整体赋值(除非使用
- 动态数组需
new
:int dyn_arr[]; dyn_arr = new[4]; // 动态分配
- 维度顺序:
从左到右由高到低(类似 C 语言多维数组)。logic [1:0][3:0] matrix; // 2×4 位,共 8 位
matrix[1]
访问第 1 个 4 位元素(bits 4-7)。
- 维度顺序:
从右到左由高到低(类似 Verilog 传统数组)。logic [3:0] matrix [0:1]; // 2 个独立的 4 位元素
matrix[1]
访问第 1 个 4 位元素(独立存储)。
- 硬件信号建模:
- 寄存器、总线、协议字段(如 32 位数据总线)。
logic [31:0] data_bus; // 合并数组
- 位级操作:
- 状态机编码、位掩码、CRC 计算。
logic [7:0] crc = 8'hFF; crc = crc ^ data[0];
- 存储大量数据:
- RAM、ROM、测试平台数据缓冲区。
logic [7:0] memory [0:1023]; // 1KB 存储器
- 动态数据结构:
- 动态数组、队列、关联数组。
int dyn_arr[]; // 动态数组 dyn_arr = new[100];