在Verilog中乘以2D数组

时间:2013-10-03 17:11:24

标签: arrays verilog

我正在尝试将我的k最近邻居代码(在MATLAB中)移植到Verilog,以便我可以在我的设计中使用它并最终放在FPGA板上。现在,代码及其操作在MATLAB中相当简单,因为制作null和identity矩阵或乘以2D矩阵之类的东西可以通过预构建函数方便地处理。我试图在Verilog中做同样的事情,但没有使用'for'循环,因为它们只用于并行结构而不是非常有效(对吧?)。我可以处理一维数组,但我似乎无法想到任何有效的二维矩阵(或者至少与硬件上的数据一样高效)。任何建议都会有所帮助。

提前致谢!!

2 个答案:

答案 0 :(得分:2)

不幸的是,我认为这最终将成为一个比你预期的更大的项目。

请记住,verilog不是一种编程语言,而是一种硬件描述语言。它不知道你是在尝试进行大型的数学计算,两个数字的单个乘法运算是你可以获得的最高抽象级别。

因此,您必须考虑进入矩阵乘法的所有单独的加/乘运算,并考虑如何编写可以执行每个操作的状态机,同时跟踪所有中间产品。

即使是4x4矩阵乘法也需要超过一百个加法/乘法运算,并且您将不得不描述一个知道并且可以跟踪所有这些的处理器。

我认为对于Verilog的新人而言,这可能是一个多周的项目来计划,编写和验证矩阵乘法电路,而不是单行语句。我知道这不是一个具体的答案,但只是想让你了解这个项目的范围。

如果你想尝试它,首先要确定你能够实例化多少并行乘法器和加法器,然后开始思考如何编写一个可以跟踪所有单独的加法/乘法运算的状态机,以及那么如何在尽可能短的时钟周期内将所有乘法器和加法器并行排除所有这些操作。

答案 1 :(得分:0)

for循环是你的朋友,但只有当它在生成中使用时才会使用,而不是在顺序代码中使用(always / initial / function / task)。如果你不小心,顺序for循环可能会导致复杂的硬件。

您基本上可以使用与任何其他语言相同的方式对此进行编码,其中(主要)问题是您无法通过模块端口传递数组。下面的工作测试示例。这在VHDL中可能更容易和更清晰(可能是SV,我不使用)。如果你要做很多这类事情,而你刚开始就应该改变语言。

下面乘以3x3方阵的硬件很快,代价是硬件很多。它产生9个MAC单元,每个单元需要三个乘法器和两个加法器。你需要考虑位宽;它所代表的代码将MAC结果分配给一个18位值,这通常不起作用(代码模拟正确,因为AB中的值很小。)

您需要考虑资源和时间安排。如果你没有27个乘法器和18个加法器,但是你不需要匆忙的答案,那就分享它们吧。在极限情况下,您可以构建非常紧凑的串行硬件,代价是大量的周期和复杂的控制。

module top;

   wire[17:0]A[1:3][1:3];    // the matrices
   wire[17:0]B[1:3][1:3];
   wire[17:0]C[1:3][1:3];

   wire[(9*18)-1:0] Abits;   // bit-decomposed versions of the above
   wire[(9*18)-1:0] Bbits;
   wire[(9*18)-1:0] Cbits;

   genvar i,j;

   // set A and B with initial values
   generate 
      for(i=0; i<3; i=i+1)
         for(j=0; j<3; j=j+1) begin
            assign A[i+1][j+1] = i*3 + j;
            assign B[i+1][j+1] = i*3 + j + 1;
         end
   endgenerate

   // decompose A and B, set C
   generate 
      for(i=1; i<=3; i=i+1)
         for(j=1; j<=3; j=j+1) begin
            assign Abits[(((i-1)*3 + (j-1)) * 18)+17 -:18] = A[i][j];
            assign Bbits[(((i-1)*3 + (j-1)) * 18)+17 -:18] = B[i][j];
            assign C[i][j] = Cbits[(((i-1)*3 + (j-1)) * 18)+17 -:18];
         end
   endgenerate

   initial
      #1 $display("%4d %4d %4d\n%4d %4d %4d\n%4d %4d %4d\n",
                  C[1][1], C[1][2],C[1][3],
                  C[2][1], C[2][2],C[2][3],
                  C[3][1], C[3][2],C[3][3]);

   mmult3x3 U1(Abits, Bbits, Cbits);
endmodule

module mmult3x3
   (input  wire[(9*18)-1:0] AI,
    input  wire[(9*18)-1:0] BI,
    output wire[(9*18)-1:0] CO);

   wire[17:0]A[1:3][1:3];
   wire[17:0]B[1:3][1:3];
   wire[17:0]C[1:3][1:3];

   genvar i,j;

   generate 
      for(i=1; i<=3; i=i+1)
         for(j=1; j<=3; j=j+1) begin
            assign A[i][j] = AI[(((i-1)*3 + (j-1)) * 18)+17 -:18];
            assign B[i][j] = BI[(((i-1)*3 + (j-1)) * 18)+17 -:18];
            assign CO[(((i-1)*3 + (j-1)) * 18)+17 -:18] = C[i][j];
         end
   endgenerate

   // this is the bit that matters - everything else just works around shortcomings 
   // in the language:
   generate 
      for(i=1; i<=3; i=i+1)
         for(j=1; j<=3; j=j+1)
            assign C[i][j] = A[i][1]*B[1][j] + A[i][2]*B[2][j] + A[i][3]*B[3][j];
   endgenerate
endmodule