如何让verilog支持二维数组,三维数组作为I/O ports

发布于:2024-12-09 ⋅ 阅读:(247) ⋅ 点赞:(0)

写在前面

先看看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

网站公告

今日签到

点亮在社区的每一天
去签到