diff options
Diffstat (limited to 'techlibs/common')
-rw-r--r-- | techlibs/common/mul2dsp.v | 256 |
1 files changed, 111 insertions, 145 deletions
diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v index 8e37201e2..75b1242a2 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),
@@ -69,7 +93,7 @@ module \$mul (A, B, Y); .Y(Y)
);
`endif
- else if (A_WIDTH < B_WIDTH)
+ else if (_TECHMAP_CELLTYPE_ == "$mul" && A_WIDTH < B_WIDTH)
\$mul #(
.A_SIGNED(B_SIGNED),
.B_SIGNED(A_SIGNED),
@@ -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
|