Verilog编程陷阱——数组的声明和使用

一.数组的声明

wire [31 : 0] a_array [11 : 0]; // 12个32位wire型变量构成的数组
reg  [31 : 0] b_array [11 : 0]; // 12个32位reg型变量构成的数组
wire [31 : 0] c_array [12 : 1]; // 12个32位wire型变量构成的数组
wire [31 : 0] d_array [18 : 7]; // 12个32位wire型变量构成的数组
wire [31 : 0] e_array [0 : 11]; // 12个32位wire型变量构成的数组
wire [31 : 0] e_array [3 : 14]; // 12个32位wire型变量构成的数组

声明语法:变量类型 数组名 [a : b]

其中,a,b的位置可以调换,(a-b)的绝对值 + 1等于数组元素的个数。

在C语言中,数组只需要指定类型和元素个数,语法如下:

变量类型 数组名 [元素个数]

int a_array [12]

但在Verilog中,并不能直接指定元素个数(SV中引入了这个功能,但Verilog中不行),而是采用区间表示,像 [0 : 11],[11 : 0],[18 : 7]都可以表示区间,它们都表示数组内的元素个数为12

二. 数组的初始化

reg [31 : 0] addr_array [6 : 2];
always @(posedge clk) begin
  addr_array[2] <= 'h8;   // 12 注意这里是从2开始,与数组的定义对应,不存在addr_array[0]和addr_array[1]
  addr_array[3] <= 'h14;  // 20
  addr_array[4] <= 'h18;  // 24
  addr_array[5] <= 'h20;  // 32
  addr_array[6] <= 'h24;  // 36
end

使用时序逻辑对数组进行初始化,这相当于定义了一个ROM。

这里其实就很可能掉入陷阱,一般我们可能认为,数组的区间仅用于表示元素个数,数组元素的索引一直都是从0开始,到元素个数-1结束。这对于以下两个数组来说是对的,

reg [31 : 0] a_array [4 : 0];
// 或者
reg [31 : 0] b_array [0 : 4];

但对于上面的reg [31 : 0] addr_array [6 : 2]不对。[6 : 2]这种写法不仅表示了数组的元素个数,还额外规定了数组的索引。

Verilog的这个语法是为了具体规定每个元素在寄存器中存储的位置,是有它的作用在的,但我们很可能参考C语言的规则去理解这个数组的语法,而错误的去访问addr_array[0]addr_array[1],其实这两个元素是未定义的,根本不存在与数组中

更难受的是,赋值和使用addr_array[0]addr_array[1]这两个原本不存在的元素,综合和实现都不报错!这简直是灾难,可能导致很多令人费解的程序错误。

三. 推荐写法

为避免掉入陷阱和使用的方便,推荐仅使用以下的写法来声明数组

reg [31 : 0] addr_array [0 : 4];
always @(posedge clk) begin
  addr_array[0] <= 'h8;
  addr_array[1] <= 'h14;
  addr_array[2] <= 'h18;
  addr_array[3] <= 'h20;
  addr_array[4] <= 'h24;
end

reg/wire [m-1 : 0] 数组名 [0 : n-1]

这样声明了一个:由n个位宽为m的reg/wire型变量组成的数组。这种写法也方便检查访问数组元素是否正确,0~4正好对应每个元素的索引值。

你可能感兴趣的:(Verilog,verilog,数组,初始化,Verilog语法,编程陷阱)