【问题标题】:How to design a 64 x 64 bit array multiplier in Verilog?如何在 Verilog 中设计一个 64 x 64 位数组乘法器?
【发布时间】:2013-05-23 07:45:55
【问题描述】:

我知道如何设计一个 4x4 数组乘法器,但如果我遵循相同的逻辑,编码就会变得乏味。

  • 4 x 4 - 16 个部分产品
  • 64 x 64 - 4096 个部分产品。

除了 8 个全加器和 4 个半加器,对于 64 x 64 位,我需要多少个全加器和半加器。如何减少部分产品的数量?有什么简单的方法可以解决吗?

【问题讨论】:

    标签: verilog multiplication


    【解决方案1】:

    每当对重复模式进行繁琐的编码时,您都应该使用 generate 语句:

    module array_multiplier(a, b, y);
    
    parameter width = 8;
    input [width-1:0] a, b;
    output [width-1:0] y;
    
    wire [width*width-1:0] partials;
    
    genvar i;
    assign partials[width-1 : 0] = a[0] ? b : 0;
    generate for (i = 1; i < width; i = i+1) begin:gen
        assign partials[width*(i+1)-1 : width*i] = (a[i] ? b << i : 0) +
                                       partials[width*i-1 : width*(i-1)];
    end endgenerate
    
    assign y = partials[width*width-1 : width*(width-1)];
    
    endmodule
    

    我已使用以下测试台验证了此模块: http://svn.clifford.at/handicraft/2013/array_multiplier/array_multiplier_tb.v

    编辑:

    正如@Debian 要求的流水线版本 - 就在这里。这次在数组部分的始终区域中使用 for 循环。

    module array_multiplier_pipeline(clk, a, b, y);
    
    parameter width = 8;
    
    input clk;
    input [width-1:0] a, b;
    output [width-1:0] y;
    
    reg [width-1:0] a_pipeline [0:width-2];
    reg [width-1:0] b_pipeline [0:width-2];
    reg [width-1:0] partials [0:width-1];
    integer i;
    
    always @(posedge clk) begin
        a_pipeline[0] <= a;
        b_pipeline[0] <= b;
        for (i = 1; i < width-1; i = i+1) begin
            a_pipeline[i] <= a_pipeline[i-1];
            b_pipeline[i] <= b_pipeline[i-1];
        end
    
        partials[0] <= a[0] ? b : 0;
        for (i = 1; i < width; i = i+1)
            partials[i] <= (a_pipeline[i-1][i] ? b_pipeline[i-1] << i : 0) +
                    partials[i-1];
    end
    
    assign y = partials[width-1];
    
    endmodule
    

    请注意,对于许多综合工具,也可以在非流水线加法器之后添加(宽度)寄存器阶段,并让工具寄存器平衡通过进行流水线操作。

    【讨论】:

    • 如果我必须流水线怎么办?我该怎么做,是不是有点难?
    • 我现在还在我的答案中添加了一个流水线版本(参见上面的编辑)。
    • 我知道它很久了。你能重新评估你的代码吗?输出 [width-1:0] y; // 不应该是 [2*width - 1] y ;
    • @chitranna 您当然也可以创建一个具有 2*width 输出大小的乘数。但它需要更多的改变,而不仅仅是“y”的大小:对于无符号乘法,它应该足以增加部分的大小。对于有符号乘法,它变得有点复杂。 (只要输入和输出宽度相同,我们就不需要区分有符号和无符号乘法)我还想补充一点,在实践中你会使用类似进位保存加法器树而不是“普通”加法器来实现乘法.
    • 这不会导致精度损失吗?另外,如果我想为 64 位无符号数的乘法编写 verilog 代码,那么精度会很重要吗?我们可以在聊天室讨论这个吗?
    【解决方案2】:

    [how to] reduce the number of partial products?
    一种比较常用的方法是修改 Booth 编码
    以更复杂的加数选择为代价,它至少几乎将它们的数量减半。
    以最简单的形式,考虑来自操作数之一的三个相邻位(重叠一个)的组,例如 b,并选择 0, a, 2a, -2a或 -a 作为加数。

    【讨论】:

      【解决方案3】:

      下面的代码只产生了预期输出的一半。

      module arr_multi(a, b, y);      
      parameter w = 8;       
      input [w-1:0] a, b;                // w-width       
      output [(2*w)-1:0] y;              // p-partials       
      wire [(2*w*w)-1:0] p;        //assign width as input bits multiplied by 
       output bits
       genvar i;        
       assign p[(2*w)-1 : 0] = a[0] ? b : 0;  //first output size bits          
        generate            
            for (i = 1; i < w; i = i+1)       
               begin        
                   assign p[(w*(4+(2*(i-1))))-1 : (w*2)*i] = (a[i]?b<<i :0) + p[(w*(4+(2* 
                      (i-2))))-1 :(w*2)*(i-1)];       
               end     
         endgenerate          
        assign y=p[(2*w*w)-1:(2*w)*(w-1)];     //taking last output size bits            
         endmodule       
      

      【讨论】:

      • 在你的答案中加入一些文字来解释你在做什么总是一个好主意,尤其是当已经有一个接受的答案或高度评价的答案时。阅读how to write a good answer
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-25
      • 1970-01-01
      • 2012-11-07
      相关资源
      最近更新 更多