一.数组的声明
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正好对应每个元素的索引值。
如果本文对你有所帮助,欢迎点赞、转发、收藏、评论让更多人看到,赞赏支持就更好了。
如果对文章内容有疑问,请务必清楚描述问题,留言评论或私信告知我,我看到会回复。
徐晓康的博客持续分享高质量硬件、FPGA与嵌入式知识,软件,工具等内容,欢迎大家关注。