我正在构建一个基于Row Adder Tree(二叉树)架构和modified baugh-wooley algorithm的带符号乘数verilog代码。
但是,当我在二叉树的后续层添加部分产品时,我面临生成循环的问题。
你们有任何想法如何摆脱这些错误吗?
使用生成循环是唯一可行的方法(给定大量的被乘数和乘数)来跨二叉树的层添加部分乘积?
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://stackoverflow.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:错误:无法在'test.mul.middle_layers中绑定wire / reg / memory'interm_layers [(layer) - ('sd1)]。middle_rows [('sd1)<<(pp_index)]' 1]”
design.sv:108:错误:无法绑定wire / reg / memory'interm_layers [(layer) - ('sd1)]。middle_rows [(('sd1)<<(pp_index))+('sd1)]'in 'test.mul.middle_layers [1]'
精心制作期间出现2个错误。
你的错误是你的代码中没有名为multiple_layers[0]
的块。你开始
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
所以,对前一个块的最后一次引用失败了。
我猜你需要类似下面这样的东西
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