如何在Verilog中设计一个64 x 64位的数组乘法器?

8

我知道如何设计一个4x4的数组乘法器,但如果我按照相同的逻辑,编码将变得很繁琐。

  • 4 x 4 - 16个部分积
  • 64 x 64 - 4096个部分积。

除了8个全加器和4个半加器外,我需要多少个全加器和半加器来实现64 x 64位?如何减少部分积的数量?有没有简单的方法来解决这个问题?

3个回答

10

每当你烦琐地编写重复的模式时,应该使用生成语句:

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的要求,这里提供了一个流水线版本。这次在always区域中使用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

请注意,许多综合工具也可以在非流水线加法器后添加(宽度)寄存器级别,并让工具的寄存器平衡传递进行流水线处理。


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

0

[如何] 减少部分积的数量?
一种常用的方法是修改 Booth 编码
虽然需要更复杂的加数选择,但至少可以将它们的数量减半。
在其最简单的形式中,考虑从操作数之一(例如,b)中选择三个相邻位组(重叠一个),并选择0、a、2a、-2a-a作为加数。


-1
下面的代码只生成了预期输出的一半。
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       

在回答中加入一些文本来解释你正在做什么总是一个好主意,特别是当已经有一个被接受的答案或高评分答案时。阅读如何撰写一个好的答案 - Léa Gris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接