1

我正在尝试将我的 k 最近邻代码(在 MATLAB 中)移植到 Verilog,以便我可以在我的设计中使用它并最终放在 FPGA 板上。现在,代码及其操作在 MATLAB 中相当简单,因为诸如制作空矩阵和单位矩阵或乘以 2D 矩阵之类的事情都可以通过预构建的函数方便地处理。我试图在 Verilog 中做同样的事情,但不使用“for”循环,因为它们仅用于并行结构并且效率不高(对吗?)。我可以处理一维数组,但我似乎想不出任何有效的二维矩阵(或至少与硬件一样有效)。任何意见将是有益的。

提前致谢!!

4

2 回答 2

2

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

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

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

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

我猜想对于刚接触 Verilog 的人来说,这不是一个单行语句,而是一个计划、编写和验证矩阵乘法电路的多周项目。我知道这不是一个具体的答案,只是想让你知道这个项目的范围。

如果你想尝试它,首先决定你可以实例化多少个并行乘法器和加法器,然后开始考虑如何编写一个可以跟踪所有单独的加法/乘法操作的状态机,然后如何在尽可能少的时钟周期内将所有这些操作并行地分配给您可用的所有乘法器和加法器。

于 2013-10-03T17:30:10.220 回答
0

for 循环是您的朋友,但仅当它用于生成时,而不是在顺序代码中(always/// )。如果您不小心,顺序 for 循环可能会导致复杂的硬件。initialfunctiontask

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

下面的 3x3 方阵乘法的硬件速度很快,但会消耗大量硬件。它生成 9 个 MAC 单元,每个 MAC 单元需要三个乘法器和两个加法器。您需要考虑位宽;目前的代码将 MAC 结果分配给一个 18 位值,这通常不起作用(代码正确模拟,因为 和 的值A很小B)。

你需要考虑资源和时间。如果你还没有 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
于 2013-10-04T12:06:27.920 回答