Verilog 数组与存储器:掌握多维数据结构
数组 声明的线网或变量可以是标量或向量。通过在标识符名后指定地址范围可创建任意维度数组,称为多维数组。Verilog 允许 reg、wire、integer 和 real 数据类型形成数组。
reg y1 [11:0]; // y1 是标量 reg 数组,深度=12,每个 1 位宽
wire [0:7] y2 [3:0] // y2 是 8位向量线网,深度=4
reg [7:0] y3 [0:1][0:3]; // y3 是二维数组,行=2,列=4,每个 8位宽
访问数组特定元素需为每个维度指定索引,索引可以是其他变量的表达式。数组可用于 Verilog 支持的所有数据类型。
注意:n 个 1 位 reg 组成的存储器不等同于 n 位向量 reg。
赋值
y1 = 0; // 非法 - 不能一次性赋值所有元素
y2[0] = 8'ha2; // 索引 0 赋 0xa2
y2[2] = 8'h1c; // 索引 2 赋 0x1c
y3[1][2] = 8'hdd; // 行=1 列=2 赋 0xdd
y3[0][0] = 8'haa; // 行=0 列=0 赋 0xaa
示例
下面代码展示如何建模、赋值和访问不同数组。mem1 是 8 位向量,mem2 是深度 4 的 8 位向量数组(范围 [0:3]),mem3 是 4 行 2 列的 16 位向量二维数组。这些变量被赋予不同值并打印。
module des ();
reg [7:0] mem1; // 8位 reg 向量
reg [7:0] mem2 [0:3]; // 8位向量数组,深度=4
reg [15:0] mem3 [0:3][0:1]; // 16位向量二维数组,行=4,列=2
initial begin
int i;
mem1 = 8'ha9;
$display ("mem1 = 0x%0h", mem1);
mem2[0] = 8'haa;
mem2[1] = 8'hbb;
mem2[2] = 8'hcc;
mem2[3] = 8'hdd;
for(i = 0; i < 4; i = i+1) begin
$display("mem2[%0d] = 0x%0h", i, mem2[i]);
end
for(int i = 0; i < 4; i += 1) begin
for(int j = 0; j < 2; j += 1) begin
mem3[i][j] = i + j;
$display("mem3[%0d][%0d] = 0x%0h", i, j, mem3[i][j]);
end
end
end
endmodule
仿真日志
ncsim> run mem1 = 0xa9 mem2[0] = 0xaa mem2[1] = 0xbb mem2[2] = 0xcc mem2[3] = 0xdd mem3[0][0] = 0x0 mem3[0][1] = 0x1 mem3[1][0] = 0x1 mem3[1][1] = 0x2 mem3[2][0] = 0x2 mem3[2][1] = 0x3 mem3[3][0] = 0x3 mem3[3][1] = 0x4 ncsim: *W,RNQUIE: Simulation is complete.
存储器
存储器是数字存储元件,用于在数字电路中存储数据和信息。RAM 和 ROM 是典型例子。存储元件可用一维 reg 数组建模,称为 存储器。存储器每个元素可代表一个字,用单个数组索引引用。
寄存器向量
Verilog 向量在变量名左侧声明尺寸范围,综合时会实例化匹配尺寸的触发器。下面代码中,设计模块接受时钟、复位和控制信号进行读写。
包含一个 16 位存储元件 register,写时更新,读时返回当前值。当 sel 和 wr 同一时钟沿为高时写入;sel 高 wr 低时读取返回当前数据。
module des (
input clk,
input rstn,
input wr,
input sel,
input [15:0] wdata,
output [15:0] rdata
);
reg [15:0] register;
always @ (posedge clk) begin
if (!rstn) register <= 0;
else begin
if (sel & wr) register <= wdata;
else register <= register;
end
end
assign rdata = (sel & ~wr) ? register : 0;
endmodule
硬件原理图显示:当写控制逻辑激活时 16 位触发器更新,读控制逻辑配置时返回当前值。
数组
此例中 register 是数组,有 4 个位置,每个 16 位宽。设计模块额外接受 addr 信号访问数组特定索引。
module des (
input clk,
input rstn,
input [1:0] addr,
input wr,
input sel,
input [15:0] wdata,
output [15:0] rdata
);
reg [15:0] register [0:3];
integer i;
always @ (posedge clk) begin
if (!rstn) begin
for (i = 0; i < 4; i = i+1) begin
register[i] <= 0;
end
end else begin
if (sel & wr) register[addr] <= wdata;
else register[addr] <= register[addr];
end
end
assign rdata = (sel & ~wr) ? register[addr] : 0;
endmodule
硬件原理图可见数组每个索引是一个 16 位触发器,输入地址用于访问特定触发器组。
Verilog