diff options
Diffstat (limited to 'techlibs/common')
-rw-r--r-- | techlibs/common/abc9_model.v | 4 | ||||
-rw-r--r-- | techlibs/common/abc9_unmap.v | 5 | ||||
-rw-r--r-- | techlibs/common/gen_fine_ffs.py | 49 | ||||
-rw-r--r-- | techlibs/common/mul2dsp.v | 636 | ||||
-rw-r--r-- | techlibs/common/prep.cc | 15 | ||||
-rw-r--r-- | techlibs/common/simcells.v | 286 | ||||
-rw-r--r-- | techlibs/common/simlib.v | 316 | ||||
-rw-r--r-- | techlibs/common/synth.cc | 2 | ||||
-rw-r--r-- | techlibs/common/techmap.v | 43 |
9 files changed, 1002 insertions, 354 deletions
diff --git a/techlibs/common/abc9_model.v b/techlibs/common/abc9_model.v index 4fee60f75..570a1ec40 100644 --- a/techlibs/common/abc9_model.v +++ b/techlibs/common/abc9_model.v @@ -6,6 +6,10 @@ module $__ABC9_DELAY (input I, output O); endspecify endmodule +module $__ABC9_SCC_BREAKER (input [WIDTH-1:0] I, output [WIDTH-1:0] O); +parameter WIDTH = 0; +endmodule + (* abc9_flop, abc9_box, lib_whitebox *) module $__DFF_N__$abc9_flop (input C, D, Q, output n1); assign n1 = D; diff --git a/techlibs/common/abc9_unmap.v b/techlibs/common/abc9_unmap.v index c39648c62..b1bc4fb6e 100644 --- a/techlibs/common/abc9_unmap.v +++ b/techlibs/common/abc9_unmap.v @@ -9,3 +9,8 @@ module $__DFF_x__$abc9_flop (input C, D, (* init = 1'b0 *) input Q, output n1); $error("Unrecognised _TECHMAP_CELLTYPE_"); endgenerate endmodule + +module $__ABC9_SCC_BREAKER (input [WIDTH-1:0] I, output [WIDTH-1:0] O); +parameter WIDTH = 0; +assign O = I; +endmodule diff --git a/techlibs/common/gen_fine_ffs.py b/techlibs/common/gen_fine_ffs.py index 5d331e767..25c6ef171 100644 --- a/techlibs/common/gen_fine_ffs.py +++ b/techlibs/common/gen_fine_ffs.py @@ -133,6 +133,55 @@ endmodule """ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| //- +//- $_ALDFF_{C:N|P}{L:N|P}_ (D, C, L, AD, Q) +//- +//- A {C:negative|positive} edge D-type flip-flop with {L:negative|positive} polarity async load. +//- +//- Truth table: D C L AD | Q +//- ----------+--- +//- - - {L:0|1} a | a +//- d {C:\\|/} - - | d +//- - - - - | q +//- +module \$_ALDFF_{C:N|P}{L:N|P}_ (D, C, L, AD, Q); +input D, C, L, AD; +output reg Q; +always @({C:neg|pos}edge C or {L:neg|pos}edge L) begin + if (L == {L:0|1}) + Q <= AD; + else + Q <= D; +end +endmodule +""", +""" +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFFE_{C:N|P}{L:N|P}{E:N|P}_ (D, C, L, AD, E, Q) +//- +//- A {C:negative|positive} edge D-type flip-flop with {L:negative|positive} polarity async load and {E:negative|positive} +//- polarity clock enable. +//- +//- Truth table: D C L AD E | Q +//- ------------+--- +//- - - {L:0|1} a - | a +//- d {C:\\|/} - - {E:0|1} | d +//- - - - - - | q +//- +module \$_ALDFFE_{C:N|P}{L:N|P}{E:N|P}_ (D, C, L, AD, E, Q); +input D, C, L, AD, E; +output reg Q; +always @({C:neg|pos}edge C or {L:neg|pos}edge L) begin + if (L == {L:0|1}) + Q <= AD; + else if (E == {E:0|1}) + Q <= D; +end +endmodule +""", +""" +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- //- $_DFFSR_{C:N|P}{S:N|P}{R:N|P}_ (C, S, R, D, Q) //- //- A {C:negative|positive} edge D-type flip-flop with {S:negative|positive} polarity set and {R:negative|positive} diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v index f22f47b4a..ca2b3c5cf 100644 --- a/techlibs/common/mul2dsp.v +++ b/techlibs/common/mul2dsp.v @@ -1,318 +1,318 @@ -/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * 2019 Eddie Hung <eddie@fpgeh.com>
- * 2019 David Shah <dave@ds0.me>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * ---
- *
- * Tech-mapping rules for decomposing arbitrarily-sized $mul cells
- * into an equivalent collection of smaller `DSP_NAME cells (with the
- * same interface as $mul) no larger than `DSP_[AB]_MAXWIDTH, attached
- * to $shl and $add cells.
- *
- */
-
-`ifndef DSP_A_MAXWIDTH
-$fatal(1, "Macro DSP_A_MAXWIDTH must be defined");
-`endif
-`ifndef DSP_B_MAXWIDTH
-$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
-$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)
-
-(* techmap_celltype = "$mul $__mul" *)
-module _80_mul (A, B, Y);
- parameter A_SIGNED = 0;
- parameter B_SIGNED = 0;
- parameter A_WIDTH = 1;
- parameter B_WIDTH = 1;
- parameter Y_WIDTH = 1;
-
- (* force_downto *)
- input [A_WIDTH-1:0] A;
- (* force_downto *)
- input [B_WIDTH-1:0] B;
- (* force_downto *)
- output [Y_WIDTH-1:0] Y;
-
- parameter _TECHMAP_CELLTYPE_ = "";
-
- 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
-`ifdef DSP_SIGNEDONLY
- else if (_TECHMAP_CELLTYPE_ == "$mul" && !A_SIGNED && !B_SIGNED)
- \$mul #(
- .A_SIGNED(1),
- .B_SIGNED(1),
- .A_WIDTH(A_WIDTH + 1),
- .B_WIDTH(B_WIDTH + 1),
- .Y_WIDTH(Y_WIDTH)
- ) _TECHMAP_REPLACE_ (
- .A({1'b0, A}),
- .B({1'b0, B}),
- .Y(Y)
- );
-`endif
- else if (_TECHMAP_CELLTYPE_ == "$mul" && A_WIDTH < B_WIDTH)
- \$mul #(
- .A_SIGNED(B_SIGNED),
- .B_SIGNED(A_SIGNED),
- .A_WIDTH(B_WIDTH),
- .B_WIDTH(A_WIDTH),
- .Y_WIDTH(Y_WIDTH)
- ) _TECHMAP_REPLACE_ (
- .A(B),
- .B(A),
- .Y(Y)
- );
- else begin
- wire [1023:0] _TECHMAP_DO_ = "proc; clean";
-
-`ifdef DSP_SIGNEDONLY
- localparam sign_headroom = 1;
-`else
- localparam sign_headroom = 0;
-`endif
-
- 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 : blk
- (* force_downto *)
- wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
- (* force_downto *)
- wire signed [last_Y_WIDTH-1:0] last_partial;
- (* force_downto *)
- wire signed [Y_WIDTH-1:0] partial_sum [n:0];
- end
- else begin : blk
- (* force_downto *)
- wire [partial_Y_WIDTH-1:0] partial [n-1:0];
- (* force_downto *)
- wire [last_Y_WIDTH-1:0] last_partial;
- (* force_downto *)
- wire [Y_WIDTH-1:0] partial_sum [n:0];
- end
-
- for (i = 0; i < n; i=i+1) begin:sliceA
- \$__mul #(
- .A_SIGNED(sign_headroom),
- .B_SIGNED(B_SIGNED),
- .A_WIDTH(`DSP_A_MAXWIDTH_PARTIAL),
- .B_WIDTH(B_WIDTH),
- .Y_WIDTH(partial_Y_WIDTH)
- ) mul (
- .A({{sign_headroom{1'b0}}, A[i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_A_MAXWIDTH_PARTIAL-sign_headroom]}),
- .B(B),
- .Y(blk.partial[i])
- );
- // TODO: Currently a 'cascade' approach to summing the partial
- // products is taken here, but a more efficient 'binary
- // reduction' approach also exists...
- if (i == 0)
- assign blk.partial_sum[i] = blk.partial[i];
- else
- assign blk.partial_sum[i] = (blk.partial[i] << (* mul2dsp *) i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) blk.partial_sum[i-1];
- end
-
- \$__mul #(
- .A_SIGNED(A_SIGNED),
- .B_SIGNED(B_SIGNED),
- .A_WIDTH(last_A_WIDTH),
- .B_WIDTH(B_WIDTH),
- .Y_WIDTH(last_Y_WIDTH)
- ) sliceA.last (
- .A(A[A_WIDTH-1 -: last_A_WIDTH]),
- .B(B),
- .Y(blk.last_partial)
- );
- assign blk.partial_sum[n] = (blk.last_partial << (* mul2dsp *) n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) blk.partial_sum[n-1];
- assign Y = blk.partial_sum[n];
- end
- else if (B_WIDTH > `DSP_B_MAXWIDTH) begin
- 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 : blk
- (* force_downto *)
- wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
- (* force_downto *)
- wire signed [last_Y_WIDTH-1:0] last_partial;
- (* force_downto *)
- wire signed [Y_WIDTH-1:0] partial_sum [n:0];
- end
- else begin : blk
- (* force_downto *)
- wire [partial_Y_WIDTH-1:0] partial [n-1:0];
- (* force_downto *)
- wire [last_Y_WIDTH-1:0] last_partial;
- (* force_downto *)
- wire [Y_WIDTH-1:0] partial_sum [n:0];
- end
-
- for (i = 0; i < n; i=i+1) begin:sliceB
- \$__mul #(
- .A_SIGNED(A_SIGNED),
- .B_SIGNED(sign_headroom),
- .A_WIDTH(A_WIDTH),
- .B_WIDTH(`DSP_B_MAXWIDTH_PARTIAL),
- .Y_WIDTH(partial_Y_WIDTH)
- ) mul (
- .A(A),
- .B({{sign_headroom{1'b0}}, B[i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_B_MAXWIDTH_PARTIAL-sign_headroom]}),
- .Y(blk.partial[i])
- );
- // TODO: Currently a 'cascade' approach to summing the partial
- // products is taken here, but a more efficient 'binary
- // reduction' approach also exists...
- if (i == 0)
- assign blk.partial_sum[i] = blk.partial[i];
- else
- assign blk.partial_sum[i] = (blk.partial[i] << (* mul2dsp *) i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) blk.partial_sum[i-1];
- end
-
- \$__mul #(
- .A_SIGNED(A_SIGNED),
- .B_SIGNED(B_SIGNED),
- .A_WIDTH(A_WIDTH),
- .B_WIDTH(last_B_WIDTH),
- .Y_WIDTH(last_Y_WIDTH)
- ) mul_sliceB_last (
- .A(A),
- .B(B[B_WIDTH-1 -: last_B_WIDTH]),
- .Y(blk.last_partial)
- );
- assign blk.partial_sum[n] = (blk.last_partial << (* mul2dsp *) n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) blk.partial_sum[n-1];
- assign Y = blk.partial_sum[n];
- end
- else begin
- if (A_SIGNED) begin : blkA
- wire signed [`DSP_A_MAXWIDTH-1:0] Aext = $signed(A);
- end
- else begin : blkA
- wire [`DSP_A_MAXWIDTH-1:0] Aext = A;
- end
- if (B_SIGNED) begin : blkB
- wire signed [`DSP_B_MAXWIDTH-1:0] Bext = $signed(B);
- end
- else begin : blkB
- wire [`DSP_B_MAXWIDTH-1:0] Bext = B;
- end
-
- `DSP_NAME #(
- .A_SIGNED(A_SIGNED),
- .B_SIGNED(B_SIGNED),
- .A_WIDTH(`DSP_A_MAXWIDTH),
- .B_WIDTH(`DSP_B_MAXWIDTH),
- .Y_WIDTH(`MIN(Y_WIDTH,`DSP_A_MAXWIDTH+`DSP_B_MAXWIDTH)),
- ) _TECHMAP_REPLACE_ (
- .A(blkA.Aext),
- .B(blkB.Bext),
- .Y(Y)
- );
- end
- end
- endgenerate
-endmodule
-
-(* techmap_celltype = "$mul $__mul" *)
-module _90_soft_mul (A, B, Y);
- parameter A_SIGNED = 0;
- parameter B_SIGNED = 0;
- parameter A_WIDTH = 1;
- parameter B_WIDTH = 1;
- parameter Y_WIDTH = 1;
-
- (* force_downto *)
- input [A_WIDTH-1:0] A;
- (* force_downto *)
- input [B_WIDTH-1:0] B;
- (* force_downto *)
- output [Y_WIDTH-1:0] 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)
- );
- endgenerate
-endmodule
+/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> + * 2019 Eddie Hung <eddie@fpgeh.com> + * 2019 gatecat <gatecat@ds0.me> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * --- + * + * Tech-mapping rules for decomposing arbitrarily-sized $mul cells + * into an equivalent collection of smaller `DSP_NAME cells (with the + * same interface as $mul) no larger than `DSP_[AB]_MAXWIDTH, attached + * to $shl and $add cells. + * + */ + +`ifndef DSP_A_MAXWIDTH +$fatal(1, "Macro DSP_A_MAXWIDTH must be defined"); +`endif +`ifndef DSP_B_MAXWIDTH +$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 +$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) + +(* techmap_celltype = "$mul $__mul" *) +module _80_mul (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + (* force_downto *) + input [A_WIDTH-1:0] A; + (* force_downto *) + input [B_WIDTH-1:0] B; + (* force_downto *) + output [Y_WIDTH-1:0] Y; + + parameter _TECHMAP_CELLTYPE_ = ""; + + 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 +`ifdef DSP_SIGNEDONLY + else if (_TECHMAP_CELLTYPE_ == "$mul" && !A_SIGNED && !B_SIGNED) + \$mul #( + .A_SIGNED(1), + .B_SIGNED(1), + .A_WIDTH(A_WIDTH + 1), + .B_WIDTH(B_WIDTH + 1), + .Y_WIDTH(Y_WIDTH) + ) _TECHMAP_REPLACE_ ( + .A({1'b0, A}), + .B({1'b0, B}), + .Y(Y) + ); +`endif + else if (_TECHMAP_CELLTYPE_ == "$mul" && A_WIDTH < B_WIDTH) + \$mul #( + .A_SIGNED(B_SIGNED), + .B_SIGNED(A_SIGNED), + .A_WIDTH(B_WIDTH), + .B_WIDTH(A_WIDTH), + .Y_WIDTH(Y_WIDTH) + ) _TECHMAP_REPLACE_ ( + .A(B), + .B(A), + .Y(Y) + ); + else begin + wire [1023:0] _TECHMAP_DO_ = "proc; clean"; + +`ifdef DSP_SIGNEDONLY + localparam sign_headroom = 1; +`else + localparam sign_headroom = 0; +`endif + + 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 : blk + (* force_downto *) + wire signed [partial_Y_WIDTH-1:0] partial [n-1:0]; + (* force_downto *) + wire signed [last_Y_WIDTH-1:0] last_partial; + (* force_downto *) + wire signed [Y_WIDTH-1:0] partial_sum [n:0]; + end + else begin : blk + (* force_downto *) + wire [partial_Y_WIDTH-1:0] partial [n-1:0]; + (* force_downto *) + wire [last_Y_WIDTH-1:0] last_partial; + (* force_downto *) + wire [Y_WIDTH-1:0] partial_sum [n:0]; + end + + for (i = 0; i < n; i=i+1) begin:sliceA + \$__mul #( + .A_SIGNED(sign_headroom), + .B_SIGNED(B_SIGNED), + .A_WIDTH(`DSP_A_MAXWIDTH_PARTIAL), + .B_WIDTH(B_WIDTH), + .Y_WIDTH(partial_Y_WIDTH) + ) mul ( + .A({{sign_headroom{1'b0}}, A[i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_A_MAXWIDTH_PARTIAL-sign_headroom]}), + .B(B), + .Y(blk.partial[i]) + ); + // TODO: Currently a 'cascade' approach to summing the partial + // products is taken here, but a more efficient 'binary + // reduction' approach also exists... + if (i == 0) + assign blk.partial_sum[i] = blk.partial[i]; + else + assign blk.partial_sum[i] = (blk.partial[i] << (* mul2dsp *) i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) blk.partial_sum[i-1]; + end + + \$__mul #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(last_A_WIDTH), + .B_WIDTH(B_WIDTH), + .Y_WIDTH(last_Y_WIDTH) + ) sliceA.last ( + .A(A[A_WIDTH-1 -: last_A_WIDTH]), + .B(B), + .Y(blk.last_partial) + ); + assign blk.partial_sum[n] = (blk.last_partial << (* mul2dsp *) n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) blk.partial_sum[n-1]; + assign Y = blk.partial_sum[n]; + end + else if (B_WIDTH > `DSP_B_MAXWIDTH) begin + 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 : blk + (* force_downto *) + wire signed [partial_Y_WIDTH-1:0] partial [n-1:0]; + (* force_downto *) + wire signed [last_Y_WIDTH-1:0] last_partial; + (* force_downto *) + wire signed [Y_WIDTH-1:0] partial_sum [n:0]; + end + else begin : blk + (* force_downto *) + wire [partial_Y_WIDTH-1:0] partial [n-1:0]; + (* force_downto *) + wire [last_Y_WIDTH-1:0] last_partial; + (* force_downto *) + wire [Y_WIDTH-1:0] partial_sum [n:0]; + end + + for (i = 0; i < n; i=i+1) begin:sliceB + \$__mul #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(sign_headroom), + .A_WIDTH(A_WIDTH), + .B_WIDTH(`DSP_B_MAXWIDTH_PARTIAL), + .Y_WIDTH(partial_Y_WIDTH) + ) mul ( + .A(A), + .B({{sign_headroom{1'b0}}, B[i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_B_MAXWIDTH_PARTIAL-sign_headroom]}), + .Y(blk.partial[i]) + ); + // TODO: Currently a 'cascade' approach to summing the partial + // products is taken here, but a more efficient 'binary + // reduction' approach also exists... + if (i == 0) + assign blk.partial_sum[i] = blk.partial[i]; + else + assign blk.partial_sum[i] = (blk.partial[i] << (* mul2dsp *) i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) blk.partial_sum[i-1]; + end + + \$__mul #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(A_WIDTH), + .B_WIDTH(last_B_WIDTH), + .Y_WIDTH(last_Y_WIDTH) + ) mul_sliceB_last ( + .A(A), + .B(B[B_WIDTH-1 -: last_B_WIDTH]), + .Y(blk.last_partial) + ); + assign blk.partial_sum[n] = (blk.last_partial << (* mul2dsp *) n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) blk.partial_sum[n-1]; + assign Y = blk.partial_sum[n]; + end + else begin + if (A_SIGNED) begin : blkA + wire signed [`DSP_A_MAXWIDTH-1:0] Aext = $signed(A); + end + else begin : blkA + wire [`DSP_A_MAXWIDTH-1:0] Aext = A; + end + if (B_SIGNED) begin : blkB + wire signed [`DSP_B_MAXWIDTH-1:0] Bext = $signed(B); + end + else begin : blkB + wire [`DSP_B_MAXWIDTH-1:0] Bext = B; + end + + `DSP_NAME #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(`DSP_A_MAXWIDTH), + .B_WIDTH(`DSP_B_MAXWIDTH), + .Y_WIDTH(`MIN(Y_WIDTH,`DSP_A_MAXWIDTH+`DSP_B_MAXWIDTH)), + ) _TECHMAP_REPLACE_ ( + .A(blkA.Aext), + .B(blkB.Bext), + .Y(Y) + ); + end + end + endgenerate +endmodule + +(* techmap_celltype = "$mul $__mul" *) +module _90_soft_mul (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + (* force_downto *) + input [A_WIDTH-1:0] A; + (* force_downto *) + input [B_WIDTH-1:0] B; + (* force_downto *) + output [Y_WIDTH-1:0] 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) + ); + endgenerate +endmodule diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc index 93b0910d6..c354956bc 100644 --- a/techlibs/common/prep.cc +++ b/techlibs/common/prep.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -61,7 +61,7 @@ struct PrepPass : public ScriptPass log(" do not run any of the memory_* passes\n"); log("\n"); log(" -rdff\n"); - log(" do not pass -nordff to 'memory_dff'. This enables merging of FFs into\n"); + log(" call 'memory_dff'. This enables merging of FFs into\n"); log(" memory read ports.\n"); log("\n"); log(" -nokeepdc\n"); @@ -79,7 +79,7 @@ struct PrepPass : public ScriptPass } string top_module, fsm_opts; - bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc, nordff; + bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc, rdff; void clear_flags() override { @@ -91,7 +91,7 @@ struct PrepPass : public ScriptPass memxmode = false; nomemmode = false; nokeepdc = false; - nordff = true; + rdff = false; } void execute(std::vector<std::string> args, RTLIL::Design *design) override @@ -137,11 +137,11 @@ struct PrepPass : public ScriptPass continue; } if (args[argidx] == "-nordff") { - nordff = true; + rdff = false; continue; } if (args[argidx] == "-rdff") { - nordff = false; + rdff = true; continue; } if (args[argidx] == "-nokeepdc") { @@ -202,7 +202,8 @@ struct PrepPass : public ScriptPass run(memxmode ? "wreduce -keepdc -memx" : "wreduce -keepdc"); } if (!nomemmode) { - run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : "")); + if (help_mode || rdff) + run("memory_dff", "(if -rdff)"); if (help_mode || memxmode) run("memory_memx", "(if -memx)"); run("opt_clean"); diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v index 27ef44232..ad1fdc817 100644 --- a/techlibs/common/simcells.v +++ b/techlibs/common/simcells.v @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -1254,6 +1254,290 @@ endmodule // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| //- +//- $_ALDFF_NN_ (D, C, L, AD, Q) +//- +//- A negative edge D-type flip-flop with negative polarity async load. +//- +//- Truth table: D C L AD | Q +//- ----------+--- +//- - - 0 a | a +//- d \ - - | d +//- - - - - | q +//- +module \$_ALDFF_NN_ (D, C, L, AD, Q); +input D, C, L, AD; +output reg Q; +always @(negedge C or negedge L) begin + if (L == 0) + Q <= AD; + else + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFF_NP_ (D, C, L, AD, Q) +//- +//- A negative edge D-type flip-flop with positive polarity async load. +//- +//- Truth table: D C L AD | Q +//- ----------+--- +//- - - 1 a | a +//- d \ - - | d +//- - - - - | q +//- +module \$_ALDFF_NP_ (D, C, L, AD, Q); +input D, C, L, AD; +output reg Q; +always @(negedge C or posedge L) begin + if (L == 1) + Q <= AD; + else + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFF_PN_ (D, C, L, AD, Q) +//- +//- A positive edge D-type flip-flop with negative polarity async load. +//- +//- Truth table: D C L AD | Q +//- ----------+--- +//- - - 0 a | a +//- d / - - | d +//- - - - - | q +//- +module \$_ALDFF_PN_ (D, C, L, AD, Q); +input D, C, L, AD; +output reg Q; +always @(posedge C or negedge L) begin + if (L == 0) + Q <= AD; + else + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFF_PP_ (D, C, L, AD, Q) +//- +//- A positive edge D-type flip-flop with positive polarity async load. +//- +//- Truth table: D C L AD | Q +//- ----------+--- +//- - - 1 a | a +//- d / - - | d +//- - - - - | q +//- +module \$_ALDFF_PP_ (D, C, L, AD, Q); +input D, C, L, AD; +output reg Q; +always @(posedge C or posedge L) begin + if (L == 1) + Q <= AD; + else + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFFE_NNN_ (D, C, L, AD, E, Q) +//- +//- A negative edge D-type flip-flop with negative polarity async load and negative +//- polarity clock enable. +//- +//- Truth table: D C L AD E | Q +//- ------------+--- +//- - - 0 a - | a +//- d \ - - 0 | d +//- - - - - - | q +//- +module \$_ALDFFE_NNN_ (D, C, L, AD, E, Q); +input D, C, L, AD, E; +output reg Q; +always @(negedge C or negedge L) begin + if (L == 0) + Q <= AD; + else if (E == 0) + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFFE_NNP_ (D, C, L, AD, E, Q) +//- +//- A negative edge D-type flip-flop with negative polarity async load and positive +//- polarity clock enable. +//- +//- Truth table: D C L AD E | Q +//- ------------+--- +//- - - 0 a - | a +//- d \ - - 1 | d +//- - - - - - | q +//- +module \$_ALDFFE_NNP_ (D, C, L, AD, E, Q); +input D, C, L, AD, E; +output reg Q; +always @(negedge C or negedge L) begin + if (L == 0) + Q <= AD; + else if (E == 1) + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFFE_NPN_ (D, C, L, AD, E, Q) +//- +//- A negative edge D-type flip-flop with positive polarity async load and negative +//- polarity clock enable. +//- +//- Truth table: D C L AD E | Q +//- ------------+--- +//- - - 1 a - | a +//- d \ - - 0 | d +//- - - - - - | q +//- +module \$_ALDFFE_NPN_ (D, C, L, AD, E, Q); +input D, C, L, AD, E; +output reg Q; +always @(negedge C or posedge L) begin + if (L == 1) + Q <= AD; + else if (E == 0) + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFFE_NPP_ (D, C, L, AD, E, Q) +//- +//- A negative edge D-type flip-flop with positive polarity async load and positive +//- polarity clock enable. +//- +//- Truth table: D C L AD E | Q +//- ------------+--- +//- - - 1 a - | a +//- d \ - - 1 | d +//- - - - - - | q +//- +module \$_ALDFFE_NPP_ (D, C, L, AD, E, Q); +input D, C, L, AD, E; +output reg Q; +always @(negedge C or posedge L) begin + if (L == 1) + Q <= AD; + else if (E == 1) + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFFE_PNN_ (D, C, L, AD, E, Q) +//- +//- A positive edge D-type flip-flop with negative polarity async load and negative +//- polarity clock enable. +//- +//- Truth table: D C L AD E | Q +//- ------------+--- +//- - - 0 a - | a +//- d / - - 0 | d +//- - - - - - | q +//- +module \$_ALDFFE_PNN_ (D, C, L, AD, E, Q); +input D, C, L, AD, E; +output reg Q; +always @(posedge C or negedge L) begin + if (L == 0) + Q <= AD; + else if (E == 0) + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFFE_PNP_ (D, C, L, AD, E, Q) +//- +//- A positive edge D-type flip-flop with negative polarity async load and positive +//- polarity clock enable. +//- +//- Truth table: D C L AD E | Q +//- ------------+--- +//- - - 0 a - | a +//- d / - - 1 | d +//- - - - - - | q +//- +module \$_ALDFFE_PNP_ (D, C, L, AD, E, Q); +input D, C, L, AD, E; +output reg Q; +always @(posedge C or negedge L) begin + if (L == 0) + Q <= AD; + else if (E == 1) + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFFE_PPN_ (D, C, L, AD, E, Q) +//- +//- A positive edge D-type flip-flop with positive polarity async load and negative +//- polarity clock enable. +//- +//- Truth table: D C L AD E | Q +//- ------------+--- +//- - - 1 a - | a +//- d / - - 0 | d +//- - - - - - | q +//- +module \$_ALDFFE_PPN_ (D, C, L, AD, E, Q); +input D, C, L, AD, E; +output reg Q; +always @(posedge C or posedge L) begin + if (L == 1) + Q <= AD; + else if (E == 0) + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_ALDFFE_PPP_ (D, C, L, AD, E, Q) +//- +//- A positive edge D-type flip-flop with positive polarity async load and positive +//- polarity clock enable. +//- +//- Truth table: D C L AD E | Q +//- ------------+--- +//- - - 1 a - | a +//- d / - - 1 | d +//- - - - - - | q +//- +module \$_ALDFFE_PPP_ (D, C, L, AD, E, Q); +input D, C, L, AD, E; +output reg Q; +always @(posedge C or posedge L) begin + if (L == 1) + Q <= AD; + else if (E == 1) + Q <= D; +end +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- //- $_DFFSR_NNN_ (C, S, R, D, Q) //- //- A negative edge D-type flip-flop with negative polarity set and negative diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 5c9efad27..b14488ff4 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -1292,6 +1292,33 @@ endmodule // -------------------------------------------------------- +module \$bmux (A, S, Y); + +parameter WIDTH = 0; +parameter S_WIDTH = 0; + +input [(WIDTH << S_WIDTH)-1:0] A; +input [S_WIDTH-1:0] S; +output [WIDTH-1:0] Y; + +wire [WIDTH-1:0] bm0_out, bm1_out; + +generate + if (S_WIDTH > 1) begin:muxlogic + \$bmux #(.WIDTH(WIDTH), .S_WIDTH(S_WIDTH-1)) bm0 (.A(A), .S(S[S_WIDTH-2:0]), .Y(bm0_out)); + \$bmux #(.WIDTH(WIDTH), .S_WIDTH(S_WIDTH-1)) bm1 (.A(A[(WIDTH << S_WIDTH)-1:WIDTH << (S_WIDTH - 1)]), .S(S[S_WIDTH-2:0]), .Y(bm1_out)); + assign Y = S[S_WIDTH-1] ? bm1_out : bm0_out; + end else if (S_WIDTH == 1) begin:simple + assign Y = S ? A[1] : A[0]; + end else begin:passthru + assign Y = A; + end +endgenerate + +endmodule + +// -------------------------------------------------------- + module \$pmux (A, B, S, Y); parameter WIDTH = 0; @@ -1318,6 +1345,26 @@ end endmodule // -------------------------------------------------------- + +module \$demux (A, S, Y); + +parameter WIDTH = 1; +parameter S_WIDTH = 1; + +input [WIDTH-1:0] A; +input [S_WIDTH-1:0] S; +output [(WIDTH << S_WIDTH)-1:0] Y; + +genvar i; +generate + for (i = 0; i < (1 << S_WIDTH); i = i + 1) begin:slices + assign Y[i*WIDTH+:WIDTH] = (S == i) ? A : 0; + end +endgenerate + +endmodule + +// -------------------------------------------------------- `ifndef SIMLIB_NOLUT module \$lut (A, Y); @@ -1326,30 +1373,9 @@ parameter WIDTH = 0; parameter LUT = 0; input [WIDTH-1:0] A; -output reg Y; - -wire lut0_out, lut1_out; +output Y; -generate - if (WIDTH <= 1) begin:simple - assign {lut1_out, lut0_out} = LUT; - end else begin:complex - \$lut #( .WIDTH(WIDTH-1), .LUT(LUT ) ) lut0 ( .A(A[WIDTH-2:0]), .Y(lut0_out) ); - \$lut #( .WIDTH(WIDTH-1), .LUT(LUT >> (2**(WIDTH-1))) ) lut1 ( .A(A[WIDTH-2:0]), .Y(lut1_out) ); - end - - if (WIDTH > 0) begin:lutlogic - always @* begin - casez ({A[WIDTH-1], lut0_out, lut1_out}) - 3'b?11: Y = 1'b1; - 3'b?00: Y = 1'b0; - 3'b0??: Y = lut0_out; - 3'b1??: Y = lut1_out; - default: Y = 1'bx; - endcase - end - end -endgenerate +\$bmux #(.WIDTH(1), .S_WIDTH(WIDTH)) mux(.A(LUT), .S(A), .Y(Y)); endmodule @@ -1890,6 +1916,30 @@ endmodule // -------------------------------------------------------- +module \$aldff (CLK, ALOAD, AD, D, Q); + +parameter WIDTH = 0; +parameter CLK_POLARITY = 1'b1; +parameter ALOAD_POLARITY = 1'b1; + +input CLK, ALOAD; +input [WIDTH-1:0] AD; +input [WIDTH-1:0] D; +output reg [WIDTH-1:0] Q; +wire pos_clk = CLK == CLK_POLARITY; +wire pos_aload = ALOAD == ALOAD_POLARITY; + +always @(posedge pos_clk, posedge pos_aload) begin + if (pos_aload) + Q <= AD; + else + Q <= D; +end + +endmodule + +// -------------------------------------------------------- + module \$sdff (CLK, SRST, D, Q); parameter WIDTH = 0; @@ -1939,6 +1989,31 @@ endmodule // -------------------------------------------------------- +module \$aldffe (CLK, ALOAD, AD, EN, D, Q); + +parameter WIDTH = 0; +parameter CLK_POLARITY = 1'b1; +parameter EN_POLARITY = 1'b1; +parameter ALOAD_POLARITY = 1'b1; + +input CLK, ALOAD, EN; +input [WIDTH-1:0] D; +input [WIDTH-1:0] AD; +output reg [WIDTH-1:0] Q; +wire pos_clk = CLK == CLK_POLARITY; +wire pos_aload = ALOAD == ALOAD_POLARITY; + +always @(posedge pos_clk, posedge pos_aload) begin + if (pos_aload) + Q <= AD; + else if (EN == EN_POLARITY) + Q <= D; +end + +endmodule + +// -------------------------------------------------------- + module \$sdffe (CLK, SRST, EN, D, Q); parameter WIDTH = 0; @@ -2182,6 +2257,34 @@ end endmodule +module \$memrd_v2 (CLK, EN, ARST, SRST, ADDR, DATA); + +parameter MEMID = ""; +parameter ABITS = 8; +parameter WIDTH = 8; + +parameter CLK_ENABLE = 0; +parameter CLK_POLARITY = 0; +parameter TRANSPARENCY_MASK = 0; +parameter COLLISION_X_MASK = 0; +parameter ARST_VALUE = 0; +parameter SRST_VALUE = 0; +parameter INIT_VALUE = 0; +parameter CE_OVER_SRST = 0; + +input CLK, EN, ARST, SRST; +input [ABITS-1:0] ADDR; +output [WIDTH-1:0] DATA; + +initial begin + if (MEMID != "") begin + $display("ERROR: Found non-simulatable instance of $memrd_v2!"); + $finish; + end +end + +endmodule + // -------------------------------------------------------- module \$memwr (CLK, EN, ADDR, DATA); @@ -2208,6 +2311,31 @@ end endmodule +module \$memwr_v2 (CLK, EN, ADDR, DATA); + +parameter MEMID = ""; +parameter ABITS = 8; +parameter WIDTH = 8; + +parameter CLK_ENABLE = 0; +parameter CLK_POLARITY = 0; +parameter PORTID = 0; +parameter PRIORITY_MASK = 0; + +input CLK; +input [WIDTH-1:0] EN; +input [ABITS-1:0] ADDR; +input [WIDTH-1:0] DATA; + +initial begin + if (MEMID != "") begin + $display("ERROR: Found non-simulatable instance of $memwr_v2!"); + $finish; + end +end + +endmodule + // -------------------------------------------------------- module \$meminit (ADDR, DATA); @@ -2233,6 +2361,30 @@ endmodule // -------------------------------------------------------- +module \$meminit_v2 (ADDR, DATA, EN); + +parameter MEMID = ""; +parameter ABITS = 8; +parameter WIDTH = 8; +parameter WORDS = 1; + +parameter PRIORITY = 0; + +input [ABITS-1:0] ADDR; +input [WORDS*WIDTH-1:0] DATA; +input [WIDTH-1:0] EN; + +initial begin + if (MEMID != "") begin + $display("ERROR: Found non-simulatable instance of $meminit_v2!"); + $finish; + end +end + +endmodule + +// -------------------------------------------------------- + module \$mem (RD_CLK, RD_EN, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA); parameter MEMID = ""; @@ -2320,6 +2472,122 @@ end endmodule +module \$mem_v2 (RD_CLK, RD_EN, RD_ARST, RD_SRST, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA); + +parameter MEMID = ""; +parameter signed SIZE = 4; +parameter signed OFFSET = 0; +parameter signed ABITS = 2; +parameter signed WIDTH = 8; +parameter signed INIT = 1'bx; + +parameter signed RD_PORTS = 1; +parameter RD_CLK_ENABLE = 1'b1; +parameter RD_CLK_POLARITY = 1'b1; +parameter RD_TRANSPARENCY_MASK = 1'b0; +parameter RD_COLLISION_X_MASK = 1'b0; +parameter RD_WIDE_CONTINUATION = 1'b0; +parameter RD_CE_OVER_SRST = 1'b0; +parameter RD_ARST_VALUE = 1'b0; +parameter RD_SRST_VALUE = 1'b0; +parameter RD_INIT_VALUE = 1'b0; + +parameter signed WR_PORTS = 1; +parameter WR_CLK_ENABLE = 1'b1; +parameter WR_CLK_POLARITY = 1'b1; +parameter WR_PRIORITY_MASK = 1'b0; +parameter WR_WIDE_CONTINUATION = 1'b0; + +input [RD_PORTS-1:0] RD_CLK; +input [RD_PORTS-1:0] RD_EN; +input [RD_PORTS-1:0] RD_ARST; +input [RD_PORTS-1:0] RD_SRST; +input [RD_PORTS*ABITS-1:0] RD_ADDR; +output reg [RD_PORTS*WIDTH-1:0] RD_DATA; + +input [WR_PORTS-1:0] WR_CLK; +input [WR_PORTS*WIDTH-1:0] WR_EN; +input [WR_PORTS*ABITS-1:0] WR_ADDR; +input [WR_PORTS*WIDTH-1:0] WR_DATA; + +reg [WIDTH-1:0] memory [SIZE-1:0]; + +integer i, j, k; +reg [WR_PORTS-1:0] LAST_WR_CLK; +reg [RD_PORTS-1:0] LAST_RD_CLK; + +function port_active; + input clk_enable; + input clk_polarity; + input last_clk; + input this_clk; + begin + casez ({clk_enable, clk_polarity, last_clk, this_clk}) + 4'b0???: port_active = 1; + 4'b1101: port_active = 1; + 4'b1010: port_active = 1; + default: port_active = 0; + endcase + end +endfunction + +initial begin + for (i = 0; i < SIZE; i = i+1) + memory[i] = INIT >>> (i*WIDTH); + RD_DATA = RD_INIT_VALUE; +end + +always @(RD_CLK, RD_ARST, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA) begin +`ifdef SIMLIB_MEMDELAY + #`SIMLIB_MEMDELAY; +`endif + for (i = 0; i < RD_PORTS; i = i+1) begin + if (RD_CLK_ENABLE[i] && RD_EN[i] && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin + // $display("Read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]); + RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; + + for (j = 0; j < WR_PORTS; j = j+1) begin + if (RD_TRANSPARENCY_MASK[i*WR_PORTS + j] && port_active(WR_CLK_ENABLE[j], WR_CLK_POLARITY[j], LAST_WR_CLK[j], WR_CLK[j]) && RD_ADDR[i*ABITS +: ABITS] == WR_ADDR[j*ABITS +: ABITS]) + for (k = 0; k < WIDTH; k = k+1) + if (WR_EN[j*WIDTH+k]) + RD_DATA[i*WIDTH+k] <= WR_DATA[j*WIDTH+k]; + if (RD_COLLISION_X_MASK[i*WR_PORTS + j] && port_active(WR_CLK_ENABLE[j], WR_CLK_POLARITY[j], LAST_WR_CLK[j], WR_CLK[j]) && RD_ADDR[i*ABITS +: ABITS] == WR_ADDR[j*ABITS +: ABITS]) + for (k = 0; k < WIDTH; k = k+1) + if (WR_EN[j*WIDTH+k]) + RD_DATA[i*WIDTH+k] <= 1'bx; + end + end + end + + for (i = 0; i < WR_PORTS; i = i+1) begin + if (port_active(WR_CLK_ENABLE[i], WR_CLK_POLARITY[i], LAST_WR_CLK[i], WR_CLK[i])) + for (j = 0; j < WIDTH; j = j+1) + if (WR_EN[i*WIDTH+j]) begin + // $display("Write to %s: addr=%b data=%b", MEMID, WR_ADDR[i*ABITS +: ABITS], WR_DATA[i*WIDTH+j]); + memory[WR_ADDR[i*ABITS +: ABITS] - OFFSET][j] = WR_DATA[i*WIDTH+j]; + end + end + + for (i = 0; i < RD_PORTS; i = i+1) begin + if (!RD_CLK_ENABLE[i]) begin + // $display("Combinatorial read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]); + RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; + end + end + + for (i = 0; i < RD_PORTS; i = i+1) begin + if (RD_SRST[i] && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i]) && (RD_EN[i] || !RD_CE_OVER_SRST[i])) + RD_DATA[i*WIDTH +: WIDTH] <= RD_SRST_VALUE[i*WIDTH +: WIDTH]; + if (RD_ARST[i]) + RD_DATA[i*WIDTH +: WIDTH] <= RD_ARST_VALUE[i*WIDTH +: WIDTH]; + end + + LAST_RD_CLK <= RD_CLK; + LAST_WR_CLK <= WR_CLK; +end + +endmodule + `endif // -------------------------------------------------------- diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index 89d6e530e..79e5933e0 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index 2ab28e6e6..91d385b80 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -59,12 +59,12 @@ module _90_simplemap_compare_ops; endmodule (* techmap_simplemap *) -(* techmap_celltype = "$pos $slice $concat $mux $tribuf" *) +(* techmap_celltype = "$pos $slice $concat $mux $tribuf $bmux" *) module _90_simplemap_various; endmodule (* techmap_simplemap *) -(* techmap_celltype = "$sr $ff $dff $dffe $adff $adffe $sdff $sdffe $sdffce $dffsr $dffsre $dlatch $adlatch $dlatchsr" *) +(* techmap_celltype = "$sr $ff $dff $dffe $adff $adffe $aldff $aldffe $sdff $sdffe $sdffce $dffsr $dffsre $dlatch $adlatch $dlatchsr" *) module _90_simplemap_registers; endmodule @@ -597,6 +597,43 @@ module _90_pmux (A, B, S, Y); assign Y = |S ? Y_B : A; endmodule +// -------------------------------------------------------- +// Demultiplexers +// -------------------------------------------------------- + +(* techmap_celltype = "$demux" *) +module _90_demux (A, S, Y); + parameter WIDTH = 1; + parameter S_WIDTH = 1; + + (* force_downto *) + input [WIDTH-1:0] A; + (* force_downto *) + input [S_WIDTH-1:0] S; + (* force_downto *) + output [(WIDTH << S_WIDTH)-1:0] Y; + + generate + if (S_WIDTH == 0) begin + assign Y = A; + end else if (S_WIDTH == 1) begin + assign Y[0+:WIDTH] = S ? 0 : A; + assign Y[WIDTH+:WIDTH] = S ? A : 0; + end else begin + localparam SPLIT = S_WIDTH / 2; + wire [(1 << (S_WIDTH-SPLIT))-1:0] YH; + wire [(1 << SPLIT)-1:0] YL; + $demux #(.WIDTH(1), .S_WIDTH(SPLIT)) lo (.A(1'b1), .S(S[SPLIT-1:0]), .Y(YL)); + $demux #(.WIDTH(1), .S_WIDTH(S_WIDTH-SPLIT)) hi (.A(1'b1), .S(S[S_WIDTH-1:SPLIT]), .Y(YH)); + genvar i; + for (i = 0; i < (1 << S_WIDTH); i = i + 1) begin + localparam [S_WIDTH-1:0] IDX = i; + assign Y[i*WIDTH+:WIDTH] = (YL[IDX[SPLIT-1:0]] & YH[IDX[S_WIDTH-1:SPLIT]]) ? A : 0; + end + end + endgenerate +endmodule + // -------------------------------------------------------- // LUTs |