FPGA基础 -- Verilog语言要素之数组_verilog 数组
Verilog 是一种用于硬件建模的硬件描述语言(HDL),其数组机制不同于软件语言,须考虑硬件资源映射、综合约束、位宽优化等硬件特性。以下是对 Verilog 中数据类型的数组使用的全面讲解,分为一维数组、二维数组、memory 数组、reg 与 wire 中数组的差异、packed 与 unpacked 数组(SystemVerilog)等方面,并指出综合注意事项与最佳实践。
一、Verilog 数组的分类
1. 一维数组(Unpacked 1D Array)
用于表示 一组具有相同位宽的数据,例如存储 32 个 8-bit 的寄存器值:
reg [7:0] memory [0:31]; // 声明32个8位的reg
✅ 这种定义常用于寄存器组、RAM 建模、状态存储等场景。
访问方式:
memory[0] = 8\'hAA; // 写入out_data = memory[3]; // 读取
2. 二维数组(Unpacked 2D Array)
二维数组常用于更复杂的数据组织形式,如帧缓存(frame buffer)、矩阵类数据:
reg [7:0] matrix [0:7][0:7]; // 8x8的矩阵
访问方式:
matrix[3][2] = 8\'h55;
⚠️ 传统 Verilog-2001 不支持二维
wire
数组(只能是reg
),但在 SystemVerilog 中支持更全面。
3. Packed Array(SystemVerilog)
打包数组(packed array)是用于多位信号的向量扩展,用于描述数据位的排列顺序,例如:
logic [3:0][7:0] data; // 4 个 8 位数据,表示为一个 32-bit 向量
等价于:
logic [31:0] data;
与 unpacked 不同,它可以直接参与位操作:
data[1] = 8\'h11; // 设置第二个8位数据
二、数组的读写操作建模
1. 组合逻辑读
always @(*) begin case (addr) 0: out = memory[0]; 1: out = memory[1]; ... endcaseend
2. 时序逻辑写
always @(posedge clk) begin if (we) memory[addr] <= data_in;end
三、数组与综合(Synthesis)注意事项
✅ 支持综合的情况
reg [n-1:0] array [0:m]
用作 寄存器文件 / BRAM 是综合工具支持的。always @(posedge clk)
方式的写操作 +reg
数组,可映射到 Block RAM。
⚠️ 不建议使用:
wire
类型数组在旧版工具中限制较多,建议统一使用reg
。- 不建议在综合模块中使用多维数组中的多维访问逻辑嵌套赋值,容易引起资源膨胀。
四、数组初始化
Verilog 不允许像 C 语言一样初始化数组。但可使用 initial
块进行手动初始化:
integer i;initial begin for (i = 0; i < 32; i = i + 1) memory[i] = 8\'h00;end
五、数组参数化与模块化设计
结合 parameter
与 generate
可实现可扩展的数组处理:
parameter DEPTH = 64;reg [7:0] fifo [0:DEPTH-1];
配合 genvar
做模块化访问:
genvar i;generate for (i = 0; i < 8; i = i + 1) begin : mem_block assign output[i] = fifo[i]; endendgenerate
六、SystemVerilog 中的增强数组(附加)
SystemVerilog 提供了更多数组类型,便于复杂建模:
static array
dynamic array
queue
associative array
❌ 这些高级特性仅用于仿真和 testbench,不可综合!
七、实际应用案例:FIFO 寄存器组建模(RTL级)
module fifo_buffer #(parameter DEPTH=16, WIDTH=8)( input clk, input rstn, input wr_en, input rd_en, input [WIDTH-1:0] din, output reg [WIDTH-1:0] dout, output reg empty, output reg full); reg [WIDTH-1:0] buffer [0:DEPTH-1]; reg [$clog2(DEPTH):0] w_ptr, r_ptr, cnt; always @(posedge clk or negedge rstn) begin if (!rstn) begin w_ptr <= 0; r_ptr <= 0; cnt <= 0; empty <= 1; full <= 0; end else begin if (wr_en && !full) begin buffer[w_ptr] <= din; w_ptr <= w_ptr + 1; cnt <= cnt + 1; end if (rd_en && !empty) begin dout <= buffer[r_ptr]; r_ptr <= r_ptr + 1; cnt <= cnt - 1; end empty <= (cnt == 0); full <= (cnt == DEPTH); end endendmodule
总结建议
reg [n-1:0] array[]
initial
+for 循环always @posedge clk
的读写建模