From 2a1b98d478918b0a17c7e509ada6e7a71bbab526 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 13 Aug 2019 10:21:24 -0700 Subject: [PATCH] Add DSP_A_MAXWIDTH_PARTIAL, refactor --- techlibs/common/mul2dsp.v | 254 ++++++++++++++------------------ techlibs/xilinx/synth_xilinx.cc | 2 +- 2 files changed, 111 insertions(+), 145 deletions(-) diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v index 8e37201e2..71d5a5454 100644 --- a/techlibs/common/mul2dsp.v +++ b/techlibs/common/mul2dsp.v @@ -27,20 +27,30 @@ */ `ifndef DSP_A_MAXWIDTH -$error("Macro DSP_A_MAXWIDTH must be defined"); +$fatal(1, "Macro DSP_A_MAXWIDTH must be defined"); `endif `ifndef DSP_B_MAXWIDTH -$error("Macro DSP_B_MAXWIDTH must be defined"); +$fatal(1, "Macro DSP_B_MAXWIDTH must be defined"); +`endif +`ifndef DSP_B_MAXWIDTH +$fatal(1, "Macro DSP_B_MAXWIDTH must be defined"); +`endif +`ifndef DSP_A_MAXWIDTH_PARTIAL +`define DSP_A_MAXWIDTH_PARTIAL `DSP_A_MAXWIDTH +`endif +`ifndef DSP_B_MAXWIDTH_PARTIAL +`define DSP_B_MAXWIDTH_PARTIAL `DSP_B_MAXWIDTH `endif `ifndef DSP_NAME -$error("Macro DSP_NAME must be defined"); +$fatal(1, "Macro DSP_NAME must be defined"); `endif `define MAX(a,b) (a > b ? a : b) `define MIN(a,b) (a < b ? a : b) -module \$mul (A, B, Y); +(* techmap_celltype = "$mul $__mul" *) +module _80_mul (A, B, Y); parameter A_SIGNED = 0; parameter B_SIGNED = 0; parameter A_WIDTH = 1; @@ -51,12 +61,26 @@ module \$mul (A, B, Y); input [B_WIDTH-1:0] B; output [Y_WIDTH-1:0] Y; + parameter _TECHMAP_CELLTYPE_ = ""; + generate - if (A_SIGNED != B_SIGNED) + if (0) begin end +`ifdef DSP_A_MINWIDTH + else if (A_WIDTH < `DSP_A_MINWIDTH) + wire _TECHMAP_FAIL_ = 1; +`endif +`ifdef DSP_B_MINWIDTH + else if (B_WIDTH < `DSP_B_MINWIDTH) + wire _TECHMAP_FAIL_ = 1; +`endif +`ifdef DSP_Y_MINWIDTH + else if (Y_WIDTH < `DSP_Y_MINWIDTH) + wire _TECHMAP_FAIL_ = 1; +`endif + else if (_TECHMAP_CELLTYPE_ == "$mul" && A_SIGNED != B_SIGNED) wire _TECHMAP_FAIL_ = 1; - // NB: A_SIGNED == B_SIGNED from here `ifdef DSP_SIGNEDONLY - else if (!A_SIGNED) + else if (_TECHMAP_CELLTYPE_ == "$mul" && !A_SIGNED) \$mul #( .A_SIGNED(1), .B_SIGNED(1), @@ -81,102 +105,53 @@ module \$mul (A, B, Y); .B(A), .Y(Y) ); - else - \$__mul #( - .A_SIGNED(A_SIGNED), - .B_SIGNED(B_SIGNED), - .A_WIDTH(A_WIDTH), - .B_WIDTH(B_WIDTH), - .Y_WIDTH(Y_WIDTH) - ) _TECHMAP_REPLACE_ ( - .A(A), - .B(B), - .Y(Y) - ); - endgenerate -endmodule - -module \$__mul (A, B, Y); - parameter A_SIGNED = 0; - parameter B_SIGNED = 0; - parameter A_WIDTH = 1; - parameter B_WIDTH = 1; - parameter Y_WIDTH = 1; - - input [A_WIDTH-1:0] A; - input [B_WIDTH-1:0] B; - output [Y_WIDTH-1:0] Y; - - wire [1023:0] _TECHMAP_DO_ = "proc; clean"; + else begin + wire [1023:0] _TECHMAP_DO_ = "proc; clean"; `ifdef DSP_SIGNEDONLY - localparam sign_headroom = 1; + localparam sign_headroom = 1; `else - localparam sign_headroom = 0; + localparam sign_headroom = 0; `endif - genvar i; - generate - if (0) begin end -`ifdef DSP_A_MINWIDTH - else if (A_WIDTH < `DSP_A_MINWIDTH) - wire _TECHMAP_FAIL_ = 1; -`endif -`ifdef DSP_B_MINWIDTH - else if (B_WIDTH < `DSP_B_MINWIDTH) - wire _TECHMAP_FAIL_ = 1; -`endif -`ifdef DSP_Y_MINWIDTH - else if (Y_WIDTH < `DSP_Y_MINWIDTH) - wire _TECHMAP_FAIL_ = 1; -`endif - else if (A_WIDTH > `DSP_A_MAXWIDTH) begin - localparam n = (A_WIDTH+`DSP_A_MAXWIDTH-sign_headroom-1) / (`DSP_A_MAXWIDTH-sign_headroom); - localparam partial_Y_WIDTH = `MIN(Y_WIDTH, B_WIDTH+`DSP_A_MAXWIDTH); - localparam last_Y_WIDTH = `MIN(partial_Y_WIDTH, B_WIDTH+A_WIDTH-(n-1)*(`DSP_A_MAXWIDTH-sign_headroom)); + genvar i; + if (A_WIDTH > `DSP_A_MAXWIDTH) begin + localparam n = (A_WIDTH-`DSP_A_MAXWIDTH+`DSP_A_MAXWIDTH_PARTIAL-sign_headroom-1) / (`DSP_A_MAXWIDTH_PARTIAL-sign_headroom); + localparam partial_Y_WIDTH = `MIN(Y_WIDTH, B_WIDTH+`DSP_A_MAXWIDTH_PARTIAL); + localparam last_A_WIDTH = A_WIDTH-n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom); + localparam last_Y_WIDTH = B_WIDTH+last_A_WIDTH; if (A_SIGNED && B_SIGNED) begin - wire signed [partial_Y_WIDTH-1:0] partial [n-2:0]; + wire signed [partial_Y_WIDTH-1:0] partial [n-1:0]; wire signed [last_Y_WIDTH-1:0] last_partial; - wire signed [Y_WIDTH-1:0] partial_sum [n-1:0]; + wire signed [Y_WIDTH-1:0] partial_sum [n:0]; end else begin wire [partial_Y_WIDTH-1:0] partial [n-1:0]; wire [last_Y_WIDTH-1:0] last_partial; - wire [Y_WIDTH-1:0] partial_sum [n-1:0]; + wire [Y_WIDTH-1:0] partial_sum [n:0]; end - \$__mul #( - .A_SIGNED(sign_headroom), - .B_SIGNED(B_SIGNED), - .A_WIDTH(`DSP_A_MAXWIDTH), - .B_WIDTH(B_WIDTH), - .Y_WIDTH(partial_Y_WIDTH) - ) mul_slice_first ( - .A({{sign_headroom{1'b0}}, A[`DSP_A_MAXWIDTH-sign_headroom-1 : 0]}), - .B(B), - .Y(partial[0]) - ); - assign partial_sum[0] = partial[0]; - - for (i = 1; i < n-1; i=i+1) begin:slice + for (i = 0; i < n; i=i+1) begin:slice \$__mul #( .A_SIGNED(sign_headroom), .B_SIGNED(B_SIGNED), - .A_WIDTH(`DSP_A_MAXWIDTH), + .A_WIDTH(`DSP_A_MAXWIDTH_PARTIAL), .B_WIDTH(B_WIDTH), .Y_WIDTH(partial_Y_WIDTH) ) mul_slice ( - .A({{sign_headroom{1'b0}}, A[i*(`DSP_A_MAXWIDTH-sign_headroom) +: `DSP_A_MAXWIDTH-sign_headroom]}), + .A({{sign_headroom{1'b0}}, A[i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_A_MAXWIDTH_PARTIAL-sign_headroom]}), .B(B), .Y(partial[i]) ); // TODO: Currently a 'cascade' approach to summing the partial // products is taken here, but a more efficient 'binary // reduction' approach also exists... - assign partial_sum[i] = (partial[i] << i*(`DSP_A_MAXWIDTH-sign_headroom)) + partial_sum[i-1]; + if (i == 0) + assign partial_sum[i] = partial[i]; + else + assign partial_sum[i] = (partial[i] << i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + partial_sum[i-1]; end - localparam last_A_WIDTH = A_WIDTH-(n-1)*(`DSP_A_MAXWIDTH-sign_headroom); \$__mul #( .A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), @@ -188,56 +163,46 @@ module \$__mul (A, B, Y); .B(B), .Y(last_partial) ); - assign partial_sum[n-1] = (last_partial << (n-1)*(`DSP_A_MAXWIDTH-sign_headroom)) + partial_sum[n-2]; - assign Y = partial_sum[n-1]; + assign partial_sum[n] = (last_partial << n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + partial_sum[n-1]; + assign Y = partial_sum[n]; end else if (B_WIDTH > `DSP_B_MAXWIDTH) begin - localparam n = (B_WIDTH+`DSP_B_MAXWIDTH-sign_headroom-1) / (`DSP_B_MAXWIDTH-sign_headroom); - localparam partial_Y_WIDTH = `MIN(Y_WIDTH, A_WIDTH+`DSP_B_MAXWIDTH); - localparam last_Y_WIDTH = `MIN(partial_Y_WIDTH, A_WIDTH+B_WIDTH-(n-1)*(`DSP_B_MAXWIDTH-sign_headroom)); + localparam n = (B_WIDTH-`DSP_B_MAXWIDTH+`DSP_B_MAXWIDTH_PARTIAL-sign_headroom-1) / (`DSP_B_MAXWIDTH_PARTIAL-sign_headroom); + localparam partial_Y_WIDTH = `MIN(Y_WIDTH, A_WIDTH+`DSP_B_MAXWIDTH_PARTIAL); + localparam last_B_WIDTH = B_WIDTH-n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom); + localparam last_Y_WIDTH = A_WIDTH+last_B_WIDTH; if (A_SIGNED && B_SIGNED) begin - wire signed [partial_Y_WIDTH-1:0] partial [n-2:0]; + wire signed [partial_Y_WIDTH-1:0] partial [n-1:0]; wire signed [last_Y_WIDTH-1:0] last_partial; - wire signed [Y_WIDTH-1:0] partial_sum [n-1:0]; + wire signed [Y_WIDTH-1:0] partial_sum [n:0]; end else begin wire [partial_Y_WIDTH-1:0] partial [n-1:0]; wire [last_Y_WIDTH-1:0] last_partial; - wire [Y_WIDTH-1:0] partial_sum [n-1:0]; + wire [Y_WIDTH-1:0] partial_sum [n:0]; end - \$__mul #( - .A_SIGNED(A_SIGNED), - .B_SIGNED(sign_headroom), - .A_WIDTH(A_WIDTH), - .B_WIDTH(`DSP_B_MAXWIDTH), - .Y_WIDTH(partial_Y_WIDTH) - ) mul_first ( - .A(A), - .B({{sign_headroom{1'b0}}, B[`DSP_B_MAXWIDTH-sign_headroom-1 : 0]}), - .Y(partial[0]) - ); - assign partial_sum[0] = partial[0]; - - for (i = 1; i < n-1; i=i+1) begin:slice + for (i = 0; i < n; i=i+1) begin:slice \$__mul #( .A_SIGNED(A_SIGNED), .B_SIGNED(sign_headroom), .A_WIDTH(A_WIDTH), - .B_WIDTH(`DSP_B_MAXWIDTH), + .B_WIDTH(`DSP_B_MAXWIDTH_PARTIAL), .Y_WIDTH(partial_Y_WIDTH) ) mul ( .A(A), - .B({{sign_headroom{1'b0}}, B[i*(`DSP_B_MAXWIDTH-sign_headroom) +: `DSP_B_MAXWIDTH-sign_headroom]}), + .B({{sign_headroom{1'b0}}, B[i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_B_MAXWIDTH_PARTIAL-sign_headroom]}), .Y(partial[i]) ); - // TODO: Currently a 'cascade' approach to summing the partial + // TODO: Currently a 'cascade' approach to summing the partial // products is taken here, but a more efficient 'binary // reduction' approach also exists... - assign partial_sum[i] = (partial[i] << i*(`DSP_B_MAXWIDTH-sign_headroom)) + partial_sum[i-1]; + if (i == 0) + assign partial_sum[i] = partial[i]; + else + assign partial_sum[i] = (partial[i] << i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + partial_sum[i-1]; end - localparam last_B_WIDTH = B_WIDTH-(n-1)*(`DSP_B_MAXWIDTH-sign_headroom); \$__mul #( .A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), @@ -249,10 +214,10 @@ module \$__mul (A, B, Y); .B(B[B_WIDTH-1 -: last_B_WIDTH]), .Y(last_partial) ); - assign partial_sum[n-1] = (last_partial << (n-1)*(`DSP_B_MAXWIDTH-sign_headroom)) + partial_sum[n-2]; - assign Y = partial_sum[n-1]; + assign partial_sum[n] = (last_partial << n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + partial_sum[n-1]; + assign Y = partial_sum[n]; end - else begin + else begin if (A_SIGNED) wire signed [`DSP_A_MAXWIDTH-1:0] Aext = $signed(A); else @@ -274,11 +239,12 @@ module \$__mul (A, B, Y); .Y(Y) ); end + end endgenerate endmodule -(* techmap_celltype = "$__mul" *) -module $__soft_mul (A, B, Y); +(* techmap_celltype = "$mul $__mul" *) +module _90_soft_mul (A, B, Y); parameter A_SIGNED = 0; parameter B_SIGNED = 0; parameter A_WIDTH = 1; @@ -292,41 +258,41 @@ module $__soft_mul (A, B, Y); // Indirection necessary since mapping // back to $mul will cause recursion generate - if (A_SIGNED && !B_SIGNED) - \$__soft__mul #( - .A_SIGNED(A_SIGNED), - .B_SIGNED(1), - .A_WIDTH(A_WIDTH), - .B_WIDTH(B_WIDTH+1), - .Y_WIDTH(Y_WIDTH) - ) _TECHMAP_REPLACE_ ( - .A(A), - .B({1'b0,B}), - .Y(Y) - ); - else if (!A_SIGNED && B_SIGNED) - \$__soft_mul #( - .A_SIGNED(1), - .B_SIGNED(B_SIGNED), - .A_WIDTH(A_WIDTH+1), - .B_WIDTH(B_WIDTH), - .Y_WIDTH(Y_WIDTH) - ) _TECHMAP_REPLACE_ ( - .A({1'b0,A}), - .B(B), - .Y(Y) - ); - else - \$__soft_mul #( - .A_SIGNED(A_SIGNED), - .B_SIGNED(B_SIGNED), - .A_WIDTH(A_WIDTH), - .B_WIDTH(B_WIDTH), - .Y_WIDTH(Y_WIDTH) - ) _TECHMAP_REPLACE_ ( - .A(A), - .B(B), - .Y(Y) - ); + if (A_SIGNED && !B_SIGNED) + \$__soft_mul #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(1), + .A_WIDTH(A_WIDTH), + .B_WIDTH(B_WIDTH+1), + .Y_WIDTH(Y_WIDTH) + ) _TECHMAP_REPLACE_ ( + .A(A), + .B({1'b0,B}), + .Y(Y) + ); + else if (!A_SIGNED && B_SIGNED) + \$__soft_mul #( + .A_SIGNED(1), + .B_SIGNED(B_SIGNED), + .A_WIDTH(A_WIDTH+1), + .B_WIDTH(B_WIDTH), + .Y_WIDTH(Y_WIDTH) + ) _TECHMAP_REPLACE_ ( + .A({1'b0,A}), + .B(B), + .Y(Y) + ); + else + \$__soft_mul #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(A_WIDTH), + .B_WIDTH(B_WIDTH), + .Y_WIDTH(Y_WIDTH) + ) _TECHMAP_REPLACE_ ( + .A(A), + .B(B), + .Y(Y) + ); endgenerate endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 265cee6d6..477b2f6f7 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -286,7 +286,7 @@ struct SynthXilinxPass : public ScriptPass if (!nodsp || help_mode) { // NB: Xilinx multipliers are signed only - run("techmap -map +/mul2dsp.v -map +/xilinx/dsp_map.v -D DSP_A_MAXWIDTH=25 -D DSP_B_MAXWIDTH=18 -D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18", "(skip if '-nodsp')"); + run("techmap -map +/mul2dsp.v -map +/xilinx/dsp_map.v -D DSP_A_MAXWIDTH=25 -D DSP_A_MAXWIDTH_PARTIAL=18 -D DSP_B_MAXWIDTH=18 -D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18", "(skip if '-nodsp')"); run("opt_expr -fine", " (skip if '-nodsp')"); run("wreduce", " (skip if '-nodsp')"); run("xilinx_dsp", " (skip if '-nodsp')"); -- 2.30.2