【问题标题】:How can I iteratively create buses of parameterized size to connect modules also iteratively created?如何迭代地创建参数化大小的总线以连接同样迭代创建的模块?
【发布时间】:2026-01-28 08:15:02
【问题描述】:

我正在尝试使用组合逻辑方法在 verilog 中创建一个乘法器模块,以便不涉及时钟。我希望模块有一个通用的定义,即我希望 Multiplier 分别接收大小为 M 和 N 位的两个因子,并返回大小为 M+N 位的乘积。

基本思想是计算部分乘积的总和,每个乘积根据其级别向左移动一定数量的位。要理解这个想法,请看以下示例:

A = A3 A2 A1 A0 和 B = B2 B1 B0

然后,A X B 会这样计算:

                  A3*B0  A2*B0  A1*B0 A0*B0
           A3*B1  A2*B1  A1*B1 A0*B1
+   A3*B2  A2*B2  A1*B2 A0*B2
____________________________________________

要计算部分乘积的和,我需要计算前两个乘积的总和 (A 乘 B0) + ([A 乘 B1]

更一般地,要计算乘积 A[M-1:0] 乘以 B[N-1:0],我们需要使用 N-1 个 RippleCarryAdder(每个定义比前一个多一位)并以某种方式将每个的输出用作下一个的两个输入之一。

到目前为止,这是我不完整的verilog代码:

首先,RippleCarryAdder 参数化,这可以正常工作

module RippleCarryAdder#(parameter N = 4)(A,B,Cin,S,Cout);

input [N-1:0] A;
input [N-1:0] B;
input Cin;
output [N-1:0] S;
output Cout;
wire [N:0] CC;

assign CC[0] = Cin;
assign Cout = CC[N];
genvar i;
generate
for (i=0; i < N; i=i+1)
begin: addbit
    FullAdder unit(A[i],B[i],CC[i],S[i],CC[i+1]);
end
endgenerate

endmodule

乘数的不完整代码

module Multiplier #(parameter M = 4, N = 4)(A,B,P);

input [M-1:0] A; //Input A, size M
input [N-1:0] B; //Input B, size N
output [M+N-1:0] P;  //Output P (product), size M+N

wire [N-1:0] CC; //Bus for the carries of the RippleCarryAdders

assign CC[0] = 1'b0;

RippleCarryAdder#(M+1) adder0({1'b0,A&{M{B[0]}}},{A&{M{B[1]}},1'b0},CC[0], /*insert bus P0 here*/);

/*I want bus P0 =  (0 A[N-1]&B[0] ... A[0]&B[0]) + (A[N-1]&B[1] ... A[0]&B[1] 0) + CC[0], with CC[0] = 0 because it is the first sum */

genvar i;
generate
for (i=2; i < N; i=i+1)
begin: addPartialProduct
    RippleCarryAdder#(M+i) adder({A&{M{B[i]}},{(i{1'b0}}},/*{CC[i-1],P[i-2]}*/,CC[i-2],/*P[i-1]*/,CC[i-1]);

//When I do {CC[i-1],P[i-1]}, I mean the concatenation of the carry CC[i] (1 bit) with the product P[i-1] (several bits)


end
endgenerate

//Finally, I want P = P[N-1], the output of the last RippleCarryAdder

endmodule

所以我的问题是:如何定义这些参数化大小的 P[i] 总线,以便它们可以用于连接每对连续 RippleCarryAdder 的输入和输出?请注意,每条总线 P[i] 的大小为 (M+i+1),因为 i = 0, ..., N-1

如果不可能,还有哪些其他解决方案可以仅使用组合逻辑(不涉及时钟)制作参数化乘法器?

提前致谢。

PS:我知道有使用时钟的有效解决方案,但挑战是不使用它们。

【问题讨论】:

    标签: verilog


    【解决方案1】:

    创建和/部分乘积的菊花链数组,类似于波纹加法器中使用的进位链。这个链需要是一个二维数组。链数组的打包部分将是总和/部分产品,而未打包的部分将是级别。使用 2D 数组将意味着永远不会使用某些位,例如 S[0][M+N-1:M+1]。未使用的位将在综合过程中被优化掉。以下代码片段演示了使用波纹加法器实现的无符号乘法器的所需行为。

    wire [M+N-1:0] S [N-1:0]; // chain of sums / partial-products
    
    assign S[0][M:0] = { 1'b0 , { A & {M{B[0]}} } };
    // assign S[0][M+N-1:M+1] = {(N-1){1'b0}}; // uncomment to make probing readable
    assign P = S[N-1]; // Product
    
    genvar i;
    generate
    for (i=1; i < N; i=i+1)
    begin: addPartialProduct
        //if (i+1<N) assign S[i][M+N-1:M+i+1] = {(N-i){1'b0}}; // uncomment to make probing readable
        RippleCarryAdder#(M+i) adder(
            .A   ( S[i-1][M+i-1:0] ),
            .B   ( { A & {M{B[i]}} , {i{1'b0}} } ),
            .Cin ( 1'b0 ),
            .S   ( S[i][M+i-1:0] ),
            .Cout( S[i][M+i] ) );
    end
    endgenerate
    

    【讨论】:

    • 这是个好主意,实际上我想到了使用二维数组作为可能的解决方案。我尝试了您的代码,并且确实优化过程修剪了未使用的电线,但是当我编译项目并将其编程到 Basys 2 fpga 中时,不知何故它不起作用。所以我最终所做的只是对所有 RippleCarryAdder 使用固定大小的 M+N,并删除了它们定义的 Cout 输出,并且它起作用了。但是,我想知道是否有一种方法可以创建具有不同尺寸的二维线阵列,例如,第一行大小为 2,第二行大小为 3,依此类推。
    • 据我所知,你不能在 Verilog 中做到这一点。但这真的没什么大不了的,因为任何未使用的电线都会被修剪掉。
    • @PabloMessina 消除未使用的位和多维唯一大小数组的完整答案是复杂的评论。我在这里创建了一个自我回答:*.com/questions/20625784/…