首页 > 技术知识 > 正文

前言

Verilog中的二维数组很有用,可以使用for以及generate for配合二维数组进行使用,可以代替大量寄存器的场合,其实大量同类寄存器可以使用存储器进行代替,Verilog中可以使用二维数组对存储器进行建模。

存储器由FPGA的什么资源来构成,可以由综合属性来设定,或者由综合工具来自动设置。这不是本文的重点,具体可见:Vivado 随笔(1) 综合属性之 ram_style & rom_style?

下面一起来看Verilog中的数组以及如何使用数组对存储器进行建模。

存储器

存储器是数字存储元件,可帮助在数字电路中存储数据和信息。FPGA中的RAM以及ROM等存储器的模型大概都是如下这样,我们可以设计不同的位宽和深度: FPGA的设计艺术(18)如何使用Verilog中的数组对存储器进行建模?

在FPGA中,我们可以使用EDA工具提供的IP核对存储元件进行定制,当然也可以使用Verilog中的数组进行建模,下面介绍:

Verilog中的数组

我们还可以在verilog中创建和使用数组类型。这些在内存建模中特别有用。

为了在verilog中声明一个数组,我们只需要在变量名后添加一个额外的字段即可声明数组中有多少个元素。

下面的代码段显示了用于在Verilog中声明数组类型的常规语法。我们使用字段声明数组的大小。

// General syntax to declare an array type <type> <size> <variable_name> <elements>;

例如,假设我们要创建一个4位wire类型的数组。我们希望数组中总共有16个元素。下面的Verilog代码显示了如何创建此数组。

wire [3:0] example [15:0];

我们可以使用方括号访问数组类型中的各个元素。例如,下面的verilog代码显示了如何将Fh的值分配给示例数组中的第一个元素。

assign example[0] = 4hF;

数组允许以Verilog为reg,wire,integer和real数据类型。

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

必须指定每个维的索引才能访问数组的特定元素,并且可以是其他变量的表达式。可以为Verilog支持的任何不同数据类型形成一个数组。

y1 = 0; // Illegal – All elements cant be assigned in a single go y2[0] = 8ha2; // Assign 0xa2 to index=0 y2[2] = 8h1c; // Assign 0x1c to index=2

多维数组

在verilog 1995标准中,我们只能创建一维数组,例如上一节中使用的数组。

但是,当我们使用verilog 2001标准时,我们还可以创建具有多个维度的数组。

为此,我们只需添加另一个字段即可定义所需元素的数量。

下面的代码段显示了用于在verilog中创建2D数组的常规语法。

// General syntax to declare an array type <type> <size> <variable_name> <elements> <elements>;

举个例子,让我们考虑一下我们想从前面的例子中修改数组大小的情况。

现在,我们要创建一个变量,该变量可以存储2个元素,两个元素都有16个4位wire元素。

为此,我们只需在声明的末尾添加一个额外的字段即可。下面的代码段显示了我们将如何执行此操作。

wire [3:0] example [15:0][1:0]; reg [7:0] y3 [0:1][0:3]; // y is a 2D array rows=2,cols=4 each 8-bit wide

我们也使用与一维数组相同的方法来对多维数组赋值。但是,我们现在使用一对方括号在数组的两个维度上定义元素。

例如,假设我们要为两个维度中的最后一个元素分配Ah的值。下面的verilog代码显示了如何将数据分配给数组中的该元素。

和上面数组一样的原则:

必须指定每个维的索引才能访问数组的特定元素,并且可以是其他变量的表达式。可以为Verilog支持的任何不同数据类型形成一个数组。

y3[1][2] = 8hdd; // Assign 0xdd to rows=1 cols=2 y3[0][0] = 8haa; // Assign 0xaa to rows=0 cols=0 example [15][1] = 4ha; example [15][0] = 4ha;

数组建模以及初始化示例

mem1是一个8位向量,mem2是一个深度为4(由范围[0:3]指定)的8位数组,mem3是一个具有4行2列的16位向量2D数组。这些变量被分配了不同的值并被打印。

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 int i; mem1 = 8ha9; $display (“mem1 = 0x%0h”, mem1); mem2[0] = 8haa; mem2[1] = 8hbb; mem2[2] = 8hcc; mem2[3] = 8hdd; 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
<

最终可以得到打印结果:

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

在给一个存储器逻辑设计的例子:

在此示例中,存储器是一个深度为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位触发器,并且输入地址用于访问一组特定的触发器。

FPGA的设计艺术(18)如何使用Verilog中的数组对存储器进行建模?1

猜你喜欢