aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs/common
diff options
context:
space:
mode:
Diffstat (limited to 'techlibs/common')
-rw-r--r--techlibs/common/abc9_model.v4
-rw-r--r--techlibs/common/abc9_unmap.v5
-rw-r--r--techlibs/common/gen_fine_ffs.py49
-rw-r--r--techlibs/common/mul2dsp.v636
-rw-r--r--techlibs/common/prep.cc15
-rw-r--r--techlibs/common/simcells.v286
-rw-r--r--techlibs/common/simlib.v316
-rw-r--r--techlibs/common/synth.cc2
-rw-r--r--techlibs/common/techmap.v43
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