上篇博客
讲了单比特的变量称为标量,多比特的变量称为向量。其实向量就类似于C或者其他语言中的一维数组,如果是reg类型的变量,对应的硬件逻辑是寄存器。
本篇博文进一步延伸,Verilog中也存在多维数组,它对应的硬件逻辑可以是存储器,诸如RAM,ROM,以及FIFO等。
还是简单一些说吧,多维数组在Verilog中对应的硬件元素可以是存储器,向量,也即一维数组,可以认为是深度为0的二维数组。
由于能对应于硬件的数组,例如RAM,通常有这么几个参数,深度,宽度,因此我们一般做到二维数组,当然更多维的不是不可以,不违背语法,但用途极为有限。
reg y1
[
11
:
0
]
;
wire
[
0
:
7
]
y2
[
3
:
0
]
reg
[
7
:
0
]
y3
[
0
:
1
]
[
0
:
3
]
;
y1是一个reg类型的数组,其深度为12,宽度为1;
y2是一个wire类型的数组,其深度为4,宽度为8;
y3是一个多维(三维)数组,其意义不在多说。
上面的第二位定义,我们需要强调一下,还是统一规则为好,也就是宽度最好是高位在左,低位在右。
例如:
reg [0:0] y1 [11:0];
wire [7:0] y2 [3:0]
对于多维数组赋值,也就是对存储器赋值,我们不能像如下方式:
reg [7:0] a [15:0] = 0;
这种方式是错误的,我们需要选中对应的元素进行赋值,例如:
reg [7:0] a [15:0];
initial begin
a[0] = 16'h0000;
a[1] = 16'h0101;
a[0][0] = 1'b0;
a[0][1] = 1'b1;
for(integer i = 0; i <16; i = i + 1) begin
a[i] <= 0;
上面的例子是在仿真文件中,当然在FPGA内,如此赋初值也是可以的,但更常用的还是通过系统函数readmemh:
$readmemh("file_name", mem_array, start_addr, stop_addr);
举一个仿真的例子:
module des ();
reg [7:0] mem1;
reg [7:0] mem2 [0:3];
reg [15:0] mem3 [0:3][0:1];
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]);
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]);
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等,它们可以使用二维数组进行建模。
例如:

mem就是一个深度为256,宽度为8bit的内存空间,而它在Verilog中就是通过一个二维数组建模的。
寄存器变量,相当于一个一维数组,下面定义一个寄存器变量,并对其进行操作:复位有效时,对寄存器变量赋初值,当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;
register <= register;
assign rdata = (sel & ~wr) ? register : 0;
endmodule
硬件原理图显示,当写的控制逻辑处于有效状态时,会更新一个16位的触发器,当读的控制逻辑使能时,会返回当前值。
同理,举一个二位数组的例子:
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 else begin
if (sel & wr)
register[addr] <= wdata;
register[addr] <= register[addr];
assign rdata = (sel & ~wr) ? register[addr] : 0;
endmodule
在硬件原理图中可以看到,数组的每个索引都是一个16位的触发器,输入地址用于访问特定的触发器。

Verilog-1995只允许一维数组,而Verilog-2001允许多维数组。
//1-dimensional array of 8-bit reg variables
//(allowed
转自:https://reborn.blog.csdn.net/article/details/106974813
写在前面正文
多维数组多维数组赋值内存寄存器变量应用实例寄存器阵列应用实例
参考资料交个朋友
多维数组多维数组的使用一维数组举例二维数组举例三维数组举例从数组取若干BIT
多维数组的使用
Verilog-1995只允许一维数组,而Verilog-2001允许多维数组。
一维数组举例
//1-dimensional array of 8-bit reg variables
//(allowed in Verilog-1995 and Verilog-2001)
reg [7:0] arr...
Verilog数组表示及初始化,以三维数组为例,二维及一维应该类似;
reg [19:0] array1 [0:7][0:15][0:8]; //3维数组,用来存储梯度直方图
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
//array1 [0:7][0:15][0:8]
[code=plain]
// Note: pack 2-dim array to 1-dim array
`define PACK_ARRAY(PK_WIDTH, PK_LEN, PK_SRC, PK_DEST) \
generate \
genvar pk_idx; \
for (pk_idx=0; pk_idx<(PK_LEN); pk_idx=pk_idx+1) \
begin \
assign PK_DEST[((PK_WIDTH)*pk_idx+((PK_WIDTH)-1)):((PK_WIDTH)*pk_idx)] = PK_SRC[pk_idx][((PK_WIDTH)-1):0]; \
end \
endgenerate
// Note: unpack 1-dim array to 2-dim array
`define UNPACK_ARRAY(PK_WIDTH, PK_LEN, PK_DEST, PK_SRC) \
generate \
genvar unpk_idx; \
for (unpk_idx=0; unpk_idx<(PK_LEN); unpk_idx=unpk_idx+1) \
begin \
assign PK_DEST[unpk_idx][((PK_WIDTH)-1):0] = PK_SRC[((PK_WIDTH)*unpk_idx+(PK_WIDTH-1)):((PK_WIDTH)*unpk_idx)]; \
end \
endgenerate
[/code]