写在前面
先看看verilog中的一维数组,二维数组,三维数组长啥样?
wire [31:0]data1;//一维数组
wire [31:0]data2 [0:15];//二维数组
wire [31:0]data3 [0:15][0:15];//三维数组
众所周知,verilog只支持一维数组作为I/O ports,二维数组、三维数组是不支持的。但现在就需要把二维数组、三维数组作为输入输出端口进行传输,那应该怎么办?
目前小编想到三种方法,给大家介绍一下,有错误的话欢迎指出~
第一种:打包和解包
这种思想很简单,比如你要把二维数组作为输入端口,那么在输入之前,把二维数组进行打包变成一维数组,在module内,把一维数组解包成二维数组。
首先需要定义解包和打包的宏函数:
//二维数组打包为一维数组
`define PACK_ARRAY_2_1(PK_WIDTH,PK_LEN,PK_SRC,PK_DEST) \
generate \
genvar i; \
for (i=0; i<(PK_LEN); i=i+1) \
begin \
assign PK_DEST[((PK_WIDTH)*i+((PK_WIDTH)-1)):((PK_WIDTH)*i)] = PK_SRC[i][((PK_WIDTH)-1):0]; \
end \
endgenerate
//一维数组展开为二维数组
`define UNPACK_ARRAY_1_2(PK_WIDTH,PK_LEN,PK_DEST,PK_SRC) \
generate \
genvar j; \
for (j=0; j<(PK_LEN); j=j+1) \
begin \
assign PK_DEST[j][((PK_WIDTH)-1):0] = PK_SRC[((PK_WIDTH)*j+(PK_WIDTH-1)):((PK_WIDTH)*j)]; \
end \
endgenerate
然后使用:
module example (
input [63:0] pack_4_16_in,
output [31:0] pack_16_2_out
);
wire [3:0] din [0:15];
`UNPACK_ARRAY_1_2(4,16,din,pack_4_16_in)
wire [15:0] out [0:1];
`PACK_ARRAY_2_1(16,2,out,pack_16_2_out)
endmodule
可能有小伙伴要问了,那假如我需要把三维数组作为I/O ports呢?确实,现实中也有这种应用,比如要把一个矩阵作为I/O ports。方法也同上面类似,先把三维数组打包成二维的,然后二维数组再打包成一维的,就可以把一维数组做I/O ports啦。在Module内部,如果想用矩阵的三维数组形式,就可以把一维数组解包成二维的,二维数组再解包成三维的,就可以使用矩阵形式啦。这里给出完整的宏函数:
//二维数组打包为一维数组
`define PACK_ARRAY_2_1(PK_WIDTH,PK_LEN,PK_SRC,PK_DEST) \
generate \
genvar i; \
for (i=0; i<(PK_LEN); i=i+1) \
begin \
assign PK_DEST[((PK_WIDTH)*i+((PK_WIDTH)-1)):((PK_WIDTH)*i)] = PK_SRC[i][((PK_WIDTH)-1):0]; \
end \
endgenerate
//一维数组展开为二维数组
`define UNPACK_ARRAY_1_2(PK_WIDTH,PK_LEN,PK_DEST,PK_SRC) \
generate \
genvar j; \
for (j=0; j<(PK_LEN); j=j+1) \
begin \
assign PK_DEST[j][((PK_WIDTH)-1):0] = PK_SRC[((PK_WIDTH)*j+(PK_WIDTH-1)):((PK_WIDTH)*j)]; \
end \
endgenerate
//三维数组变成二维的
`define UNPACK_ARRAY_3_2(width,row,col,src,dest)\
generate \
genvar m; \
genvar n;\
for (m=0;m<row;m=m+1)begin\
for (n=0;n<col;n=n+1)begin\
assign dest[m*col+n]=src[m][n];\
end\
end\
endgenerate
//二维数组变成三维的
//len:一维数组的元素个数
//rows--二维数组行数 cols--二维数组列数
`define PACK_ARRAY_2_3(WIDTH, LEN, ROWS, COLS, src, dest) \
generate \
genvar k;\
for (k = 0; k < LEN; k = k + 1) begin \
assign dest[k / COLS][k % COLS] = src[k]; \
end \
endgenerate
下面给出一个例子使用上述的宏函数,test模块代码如下:
module test(
input wire [15:0]data0,
output wire [15:0]out
);
parameter WIDTH = 4;
parameter LEN = 4; // 二维数组的元素个数
parameter ROWS = 2;
parameter COLS = 2;
wire [WIDTH-1:0] data1 [0:3]; // 二维数组
wire [WIDTH-1:0] data1_temp [0:3]; // 临时二维数组
wire [WIDTH-1:0] data2_temp [0:1][0:1]; // 临时三维数组
// 将一维数组 data0 转换回二维数组 data1_temp
`UNPACK_ARRAY_1_2(WIDTH, LEN, data1_temp, data0);
// 将二维数组 data1_temp 转换回三维数组 data2_temp
`PACK_ARRAY_2_3(WIDTH, LEN, ROWS, COLS, data1_temp, data2_temp);
// 将三维数组 data2 d转换为二维数组ata1
`UNPACK_ARRAY_3_2(WIDTH, ROWS, COLS, data2_temp, data1);
// 将二维数组 data1 转换为一维数组 data0
`PACK_ARRAY_2_1(WIDTH, LEN, data1, out);
endmodule
可以写一个testbench,验证data0和out的数值是一样的,说明宏函数是正确的。
第二种方法:使用systemVerilog
verilog只支持一维数组作为I/O ports,但是systemVerilog可以支持一维数组、二维数组、三维数组作为I/O ports。给一个代码示例:
module test_sv(
input wire [3:0] input_data [0:3][0:3],
output reg [3:0] output_data [0:3][0:3],
);
initial begin
integer i;
integer j;
for (i=0;i<4;i=i+1)begin
for (j=0;j<4;j=j+1)begin
output_data[i][j]<=input_data[i][j];
end
end
end
endmodule