0
votes

I am building a signed multiplier verilog code based on Row Adder Tree (binary tree) architecture and modified baugh-wooley algorithm.

However, I am facing issue with generate loop as follows when I add the partial products across subsequent layer of the binary tree.

Do you guys have any idea how to get away from those error ?

edaplayground online code

row adder tree multiplier

Is using generate loop the only feasible way (given large length of multiplicand and multiplier) to do the additions of partial products across layers of a binary tree ?

module multiply(clk, reset, in_valid, out_valid, in_A, in_B, out_C); // C=A*B

parameter A_WIDTH = 16;
parameter B_WIDTH = 16;

input clk, reset;
input in_valid; // to signify that in_A, in_B are valid
input signed [(A_WIDTH-1):0] in_A;
input signed [(B_WIDTH-1):0] in_B;
output reg signed [(A_WIDTH+B_WIDTH-1):0] out_C;
output reg out_valid; // to signify that out_C is valid

/* 
   This multiplier code architecture requires an area of O(N*M*logN) and time O(logN)
   with M being the length or bitwidth of the multiplicand

   see https://i.imgur.com/NaqjC6G.png or 
   Row Adder Tree Multipliers in http://www.andraka.com/multipli.php or
   https://pdfs.semanticscholar.org/415c/d98dafb5c9cb358c94189927e1f3216b7494.pdf#page=10
   regarding the mechanisms within all layers

   In the case of an adder tree, the adders making up the levels closer to the input 
   take up real estate (remember the structure of row adder tree).  As the size of 
   the input multiplicand bitwidth grows, it becomes more and more difficult to find a
   placement that does not use long routes involving multiple switch nodes.  The result
   is the maximum clocking speed degrades quickly as the size of the bitwidth grows.

   For signed multiplication, see also modified baugh-wooley algorithm for trick in 
   skipping sign extension, thus smaller final routed silicon area.

   https://stackguides.com/questions/54268192/understanding-modified-baugh-wooley-multiplication-algorithm/

   All layers are pipelined, so throughput = one result for each clock cycle 
   but each multiplication result still have latency = NUM_OF_INTERMEDIATE_LAYERS 
*/


// The multiplication of two numbers is equivalent to adding as many copies of one 
// of them, the multiplicand, as the value of the other one, the multiplier.

localparam SMALLER_WIDTH = (A_WIDTH <= B_WIDTH) ? A_WIDTH : B_WIDTH;
localparam LARGER_WIDTH = (A_WIDTH > B_WIDTH) ? A_WIDTH : B_WIDTH;

wire [(LARGER_WIDTH-1):0] MULTIPLICAND = (A_WIDTH > B_WIDTH) ? in_A : in_B ;
wire [(SMALLER_WIDTH-1):0] MULTIPLIPLIER = (A_WIDTH <= B_WIDTH) ? in_A : in_B ;

localparam NUM_OF_INTERMEDIATE_LAYERS = $clog2(SMALLER_WIDTH);


/*Stage 1: Binary multiplications to generate partial products rows*/

// first layer has "SMALLER_WIDTH" entries of data of width "LARGER_WIDTH"
// This resulted in a binary tree with faster vertical addition processes as we have 
// lesser (NUM_OF_INTERMEDIATE_LAYERS) rows to add
reg [(LARGER_WIDTH-1):0] partial_products [0:(SMALLER_WIDTH-1)];

generate

    genvar first_layer_index; // all partial products rows are in first layer

    for(first_layer_index=0; first_layer_index<SMALLER_WIDTH; first_layer_index=first_layer_index+1) begin: first_layer

        always @(posedge clk, posedge reset)
        begin
            if(reset) partial_products[first_layer_index] <= 0;

            else begin
                partial_products[first_layer_index] <= (MULTIPLICAND & MULTIPLIPLIER[first_layer_index]);  // generation of partial products rows
            end
        end
    end

endgenerate


/*Stage 2 : Intermediate partial products additions*/

// intermediate partial product rows
// Imagine a rhombus of height of "NUM_OF_INTERMEDIATE_LAYERS" 
// and width of "LARGER_WIDTH" being re-arranged into binary row adder tree
// such that additions can be done in O(logN) time

generate

    genvar layer;

    for(layer=1; layer<NUM_OF_INTERMEDIATE_LAYERS; layer=layer+1) begin: middle_layers

        // number of leafs (or children) in each layer within the binary tree
        localparam NUM_OF_PP_ADDITION = (SMALLER_WIDTH >> layer);

        reg [(LARGER_WIDTH+layer-1):0] middle_rows[0:(NUM_OF_PP_ADDITION-1)];

        integer pp_index; // leaf index within each layer of the tree

        always @(posedge clk, posedge reset)
        begin
            if(reset) 
            begin
                for(pp_index=0; pp_index<NUM_OF_PP_ADDITION ; pp_index=pp_index+1)
                    middle_rows[pp_index] <= 0;
            end

            else begin
                for(pp_index=0; pp_index<NUM_OF_PP_ADDITION ; pp_index=pp_index+1)
                    middle_rows[pp_index] <=
                    middle_layers[layer-1].middle_rows[1<<pp_index] +
                    (middle_layers[layer-1].middle_rows[(1<<pp_index) + 1]) << 1;
            end
        end
    end

endgenerate


/*Stage 3 : Adding the final two partial products*/

wire sign_bit = in_A[A_WIDTH-1] ^ in_B[B_WIDTH-1];

always @(posedge clk, posedge reset)
begin
    if(reset) 
    begin
        out_C <= 0;
        out_valid <= 0;
    end

    else out_C <= 0;// {sign_bit, };
end

endmodule

iverilog '-Wall' '-g2012' design.sv testbench.sv && unbuffer vvp a.out

design.sv:107: error: Unable to bind wire/reg/memory 'middle_layers[(layer)-('sd1)].middle_rows[('sd1)<<(pp_index)]' in 'test.mul.middle_layers[1]'

design.sv:108: error: Unable to bind wire/reg/memory 'middle_layers[(layer)-('sd1)].middle_rows[(('sd1)<<(pp_index))+('sd1)]' in 'test.mul.middle_layers[1]'

2 error(s) during elaboration.

1
I have been reading system Verilog standard but I have not found anything (yet) which says you can hierarchically refer to local variables in a named block. The extra complexity is that you assume the for loop generates a named block array: middle_layers[..]. You might have to move middle_rows outside the for loop and add a dimension.Oldfart

1 Answers

0
votes

your mistake is that there is no block named multiple_layers[0] in your code. you start with

for(layer=1; ...) begin: multile_layers 
    reg [(LARGER_WIDTH+layer-1):0] middle_rows;
    always begin
        reset middle rows; 
        for ... multiple_layers [layer - 1] ... 
    end
end

so, the last reference to the previous block failed.

I guess you would need something like the following

    for(layer=0; ...) begin: multile_layers 
       reg [(LARGER_WIDTH+layer-1):0] middle_rows;
       if (layer > 1) begin
          always begin 
               reset middle rows
               for ... multiple_layers [layer - 1] ... 
          end
       end
       else begin
          always begin 
               reset middle_rows 
               // no for
          end
       end
    end