# Verilog 数组与内存

# 数组

导线或变量的数组声明可以是标量或向量。通过在标识符名称后指定地址范围可以创建任意数量的维度,称为多维数组。 Verilog 中允许 regwireintegerreal 数据类型的数组。

reg         y1 [11:0];      // y is an scalar reg array of depth=12, each 1-bit wide
wire [0:7]  y2 [3:0];       // y is an 8-bit vector net with a depth of 4
reg  [7:0]  y3 [0:1][0:3];  // y is a 2D array rows=2, cols=4 each 8-bit wide
1
2
3

必须指定每个维度的索引才能访问数组的特定元素,并且可以是其他变量的表达式(但是向量中的选择操作不可以用变量索引)。可以为 Verilog 支持的任何不同数据类型创建一个数组。

注意

请注意,n 个 1 位 reg 构成的内存(memory)与 n 位 reg 向量不同。

# 赋值

y1 = 0; // Illegal - All elements can't be assigned in a single go

y2[0] = 8'ha2; // Assign 0xa2 to index=0
y2[2] = 8'h1c; // Assign 0x1c to index=2
y3[1][2] = 8'hdd; // Assign 0xdd to rows=1 cols=2
y3[0][0] = 8'haa; // Assign 0xaa to rows=0 cols=0
1
2
3
4
5
6

# 示例

下面的代码简单地显示了如何对不同的数组进行构建、赋值和访问。 mem1 是一个 8 位向量, mem2 是一个深度为 4 的 8 位数组(由范围 [0:3] 指定), mem3 是一个 4 行 2 列的 16 位向量二维数组。这些变量被赋予不同的值并被打印出来。

module des ();
    reg [7:0] mem1;             // reg vector 8-bit wide
    reg [7:0] mem2 [0:3];       // 8-bit wide vector array with depth=4
    reg [15:0] mem3 [0:3][0:1]; // 16-bit wide vector 2D array with rows=4, cols=2

    initial begin
        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 (integer i = 0; i < 4; i = i + 1) begin
            $display ("mem2[%0d] = 0x%0h", i, mem2[i]);
        end

        for (integer i = 0; i < 4; i += 1) begin
            for (integer 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

仿真日志:

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
1
2
3
4
5
6
7
8
9
10
11
12
13

# 内存

内存是数字电路中存储数据和信息的数字存储元件。 RAM 和 ROM 是此类存储元件的常见的实例。存储元素可以使用 reg 类型的一维数组进行建模,称为一块内存(memory)。内存中的每个元素都可以表示一个字(word),并使用单个数组索引进行引用。

memory

# 寄存器向量

Verilog 向量是使用变量名左侧的位宽范围声明的,这些向量会使用位宽个数的触发器来实现。在下面的代码中,设计模块接受时钟、复位和一些控制信号来读取和写入块。

它包含一个叫做 register 的 16 位存储元件,它在写入期间简单地更新,并在读取期间返回当前值。当 selwr 在同一时钟沿为高电平时写入寄存器。当 sel 为高且 wr 为低时,它返回当前数据。

module gpr( 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

硬件原理图显示,当写入控制逻辑处于活动状态时更新 16 位触发器,当控制逻辑配置为读取时返回当前值。

register

# 数组

在下面的例子中,register 是一个具有四个位置的数组,每个位置的宽度为 16 位。设计模块接受一个称为 addr 的附加输入信号来访问数组中的特定索引。

module gprs(    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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

从硬件原理图中可以看出,数组的每个索引都是一个 16 位的触发器,输入地址用于访问一组特定的触发器。

gprs

最后更新: 2022/10/4 03:41:02