【问题标题】:Verilog vector inner productVerilog 向量内积
【发布时间】:2017-03-03 08:26:56
【问题描述】:

我正在尝试实现一个 synthesizable verilog 模块,它产生 2 个向量/数组的向量积,每个包含 8 个 16 位无符号整数。设计编译器报告了symbol i must be a constant or parameter 的错误。我不知道如何解决它。这是我的代码。

module VecMul16bit (a, b, c, clk, rst);
// Two vector inner product, each has 8 elements
// Each element is 16 bits
// So the Output should be at least 2^32*2^3 = 2^35 in order to
// prevent overflow 
// Output is 35 bits
input clk;
input rst;
input [127:0] a,b;
output [35:0] c;
reg [15:0] a_cp [0:7];
reg [15:0] b_cp [0:7];
reg [35:0] c_reg;   
reg k,c_done;

integer i;
always @ (a)
begin
    for (i=0; i<=7; i=i+1) begin
        a_cp[i] = a[i*15:i*15+15];
    end
end

always @ (b)
begin 
    for (i=0; i<=7; i=i+1) begin
        b_cp[i] = b[i*15:i*15+15];
    end

end 

assign c = c_reg;

always @(posedge clk or posedge rst)
begin
    if (rst) begin
        c_reg <= 0;
        k <= 0;
        c_done <= 0;
    end else begin
        c_reg   <= c_done ? c_reg  : (c_reg + a_cp[k]*b_cp[k]);
        k           <= c_done ?         k : k + 1;
        c_done      <= c_done ?         1 : (k == 7);
    end
end

endmodule

如您所见,我正在尝试通过循环将a 复制到a_cp,这是正确的做法吗?

如果是,我应该如何定义它i 并且可以将常量用作 for 循环中的步进器?

【问题讨论】:

    标签: loops initialization verilog constants


    【解决方案1】:

    verilog 中的part select 必须有恒定的界限。所以这是不允许的:

    a_cp[i] = a[i*15:i*15+15];
    

    Verilog-2001 引入了一种新的索引部分选择语法,您可以在其中指定所选位组的起始位置和宽度。因此,您需要将上面的行替换为:

    a_cp[i] = a[i*15+:16];
    

    这需要a 的 16 位宽度切片,从位 i*15 开始向右计数。您可以使用-: 而不是+:,在这种情况下,您会向左计数。

    注意:很容易输入:+ 而不是+::+ 是有效的语法,因此您的编译器可能不会发现(但仍可能是一个错误)。事实上,我在输入 EDA Playground example 时正是这样做的,尽管在这种情况下我的错字被编译器发现了。

    【讨论】:

    • 索引可能应该移动i*16,否则切片之间会有重叠。我建议在+: 之前和之后添加空格以使其脱颖而出:a[i*15 +: 16];
    【解决方案2】:

    实际上,要使代码可合成,您需要使用 genvar 作为 i 的类型。有点像这样(使用宏,把它放在你的模块之上):

    `define PACK_ARRAY_2D2(PK_WIDTH,PK_LEN,PK_DIMS,PK_SRC,PK_DEST,PK_OFFS) ({\
     genvar pk_idx; genvar pk_dims; \
     generate \
     for (pk_idx=0; pk_idx<(PK_LEN); pk_idx=pk_idx+1) \
     begin \
        for (pk_dims=0; pk_dims<(PK_DIMS); pk_dims=pk_dims+1) \
            begin  \
        assign PK_DEST[(((PK_WIDTH)*(pk_idx+pk_dims+1))-1+((PK_WIDTH)*PK_OFFS*pk_idx)):(((PK_WIDTH)*(pk_idx+pk_dims))+((PK_WIDTH)*PK_OFFS*pk_idx))] = PK_SRC[pk_idx][pk_dims][((PK_WIDTH)-1):0];\
        end\
     end\
     endgenerate\
     }) 
    
    `define UNPACK_ARRAY_2D2(PK_WIDTH,PK_LEN,PK_DIMS,PK_DEST,PK_SRC,PK_OFFS) ({\
     genvar unpk_idx; genvar unpk_dims; \
     generate \
        for (unpk_idx=0; unpk_idx<(PK_LEN); unpk_idx=unpk_idx+1)  \
     begin \
        for (unpk_dims=0; unpk_dims<(PK_DIMS); unpk_dims=unpk_dims+1)\
      begin  \
      assign PK_DEST[unpk_idx][unpk_dims][((PK_WIDTH)-1):0] = PK_SRC[(((PK_WIDTH)*(unpk_idx+unpk_dims+1))-1+((PK_WIDTH)*PK_OFFS*unpk_idx)):(((PK_WIDTH)*(unpk_idx+unpk_dims))+((PK_WIDTH)*PK_OFFS*unpk_idx))];\
      end end endgenerate\
      })
    

    下面是如何使用它(只是放在 pack_unpack.v 中)作为转置矩阵的函数示例:

    // Macros for Matrix
    `include "pack_unpack.v"
    
    module matrix_weight_transpose(
        input signed [9*5*32-1:0] weight,               // 5 columns, 9 rows, 32 bit data length
        
        output signed [9*5*32-1:0] weight_transposed    // 9 columns, 5 rows, 32 bit data length
    );
     
     wire [31:0] weight_in [8:0][4:0];
    `UNPACK_ARRAY_2D2(32,9,5,weight_in,weight,4)
    
     wire [31:0] weight_out [4:0][8:0];
     `PACK_ARRAY_2D2(32,5,9,weight_out,weight_transposed,8)
     
     generate                                           // Computing the transpose
        genvar i;
        for (i = 0; i < 9; i = i + 1)
         begin     : columns              
         genvar j;
             for (j = 0; j < 5; j = j + 1)
             begin   : rows
                assign weight_out[j][i] = weight_in[i][j];
             end
        end
     endgenerate
    
    endmodule
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-23
      • 2017-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多