aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs/xilinx
diff options
context:
space:
mode:
authorEddie Hung <eddie@fpgeh.com>2019-12-18 12:08:38 -0800
committerEddie Hung <eddie@fpgeh.com>2019-12-18 12:08:38 -0800
commitd0afe4e10d474e9254a6d5ebc7fbeeb8e2e0149a (patch)
tree526c60c70ac41f71eb0c1a0d83f556ce1b35b126 /techlibs/xilinx
parentdccd7eb39f897f7fb04b038ee8ac11e676a8ea77 (diff)
parent520f1646cf0c0d83603c4bec2f6a37acca1d4960 (diff)
downloadyosys-d0afe4e10d474e9254a6d5ebc7fbeeb8e2e0149a.tar.gz
yosys-d0afe4e10d474e9254a6d5ebc7fbeeb8e2e0149a.tar.bz2
yosys-d0afe4e10d474e9254a6d5ebc7fbeeb8e2e0149a.zip
Merge branch 'master' of github.com:YosysHQ/yosys
Diffstat (limited to 'techlibs/xilinx')
-rw-r--r--techlibs/xilinx/Makefile.inc1
-rw-r--r--techlibs/xilinx/cells_map.v27
-rw-r--r--techlibs/xilinx/cells_sim.v35
-rw-r--r--techlibs/xilinx/cells_xtra.py2
-rw-r--r--techlibs/xilinx/cells_xtra.v21
-rw-r--r--techlibs/xilinx/synth_xilinx.cc16
-rw-r--r--techlibs/xilinx/xc6s_ff_map.v130
-rw-r--r--techlibs/xilinx/xc7_ff_map.v94
-rw-r--r--techlibs/xilinx/xilinx_dffopt.cc351
9 files changed, 617 insertions, 60 deletions
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index 3ebc72fe8..3f2fbcc85 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -1,5 +1,6 @@
OBJS += techlibs/xilinx/synth_xilinx.o
+OBJS += techlibs/xilinx/xilinx_dffopt.o
GENFILES += techlibs/xilinx/brams_init_36.vh
GENFILES += techlibs/xilinx/brams_init_32.vh
diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
index de2068bc5..cc180f2b9 100644
--- a/techlibs/xilinx/cells_map.v
+++ b/techlibs/xilinx/cells_map.v
@@ -28,6 +28,33 @@ module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1_ _TECHMAP_REPL
(* techmap_celltype = "$_DFF_PN1_" *)
module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+(* techmap_celltype = "$__DFFE_NN0" *)
+module _90_dffe_nn0_to_np0 (input D, C, R, E, output Q); \$__DFFE_NP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFE_PN0" *)
+module _90_dffe_pn0_to_pp0 (input D, C, R, E, output Q); \$__DFFE_PP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFE_NN1" *)
+module _90_dffe_nn1_to_np1 (input D, C, R, E, output Q); \$__DFFE_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFE_PN1" *)
+module _90_dffe_pn1_to_pp1 (input D, C, R, E, output Q); \$__DFFE_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+
+(* techmap_celltype = "$__DFFS_NN0_" *)
+module _90_dffs_nn0_to_np0 (input D, C, R, output Q); \$__DFFS_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+(* techmap_celltype = "$__DFFS_PN0_" *)
+module _90_dffs_pn0_to_pp0 (input D, C, R, output Q); \$__DFFS_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+(* techmap_celltype = "$__DFFS_NN1_" *)
+module _90_dffs_nn1_to_np1 (input D, C, R, output Q); \$__DFFS_NP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+(* techmap_celltype = "$__DFFS_PN1_" *)
+module _90_dffs_pn1_to_pp1 (input D, C, R, output Q); \$__DFFS_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+
+(* techmap_celltype = "$__DFFSE_NN0" *)
+module _90_dffse_nn0_to_np0 (input D, C, R, E, output Q); \$__DFFSE_NP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFSE_PN0" *)
+module _90_dffse_pn0_to_pp0 (input D, C, R, E, output Q); \$__DFFSE_PP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFSE_NN1" *)
+module _90_dffse_nn1_to_np1 (input D, C, R, E, output Q); \$__DFFSE_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFSE_PN1" *)
+module _90_dffse_pn1_to_pp1 (input D, C, R, E, output Q); \$__DFFSE_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+
module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0;
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index f9ce496ff..cf7923777 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -329,6 +329,41 @@ module FDSE (
endcase endgenerate
endmodule
+module FDRSE (
+ output reg Q,
+ (* clkbuf_sink *)
+ (* invertible_pin = "IS_C_INVERTED" *)
+ input C,
+ (* invertible_pin = "IS_CE_INVERTED" *)
+ input CE,
+ (* invertible_pin = "IS_D_INVERTED" *)
+ input D,
+ (* invertible_pin = "IS_R_INVERTED" *)
+ input R,
+ (* invertible_pin = "IS_S_INVERTED" *)
+ input S
+);
+ parameter [0:0] INIT = 1'b0;
+ parameter [0:0] IS_C_INVERTED = 1'b0;
+ parameter [0:0] IS_CE_INVERTED = 1'b0;
+ parameter [0:0] IS_D_INVERTED = 1'b0;
+ parameter [0:0] IS_R_INVERTED = 1'b0;
+ parameter [0:0] IS_S_INVERTED = 1'b0;
+ initial Q <= INIT;
+ wire c = C ^ IS_C_INVERTED;
+ wire ce = CE ^ IS_CE_INVERTED;
+ wire d = D ^ IS_D_INVERTED;
+ wire r = R ^ IS_R_INVERTED;
+ wire s = S ^ IS_S_INVERTED;
+ always @(posedge c)
+ if (r)
+ Q <= 0;
+ else if (s)
+ Q <= 1;
+ else if (ce)
+ Q <= d;
+endmodule
+
module FDCE (
(* abc9_arrival=303 *)
output reg Q,
diff --git a/techlibs/xilinx/cells_xtra.py b/techlibs/xilinx/cells_xtra.py
index e4c580b9d..6d5adf1aa 100644
--- a/techlibs/xilinx/cells_xtra.py
+++ b/techlibs/xilinx/cells_xtra.py
@@ -66,7 +66,7 @@ CELLS = [
# CLB -- registers/latches.
# Virtex 1/2/4/5, Spartan 3.
Cell('FDCPE', port_attrs={'C': ['clkbuf_sink']}),
- Cell('FDRSE', port_attrs={'C': ['clkbuf_sink']}),
+ # Cell('FDRSE', port_attrs={'C': ['clkbuf_sink']}),
Cell('LDCPE', port_attrs={'C': ['clkbuf_sink']}),
# Virtex 6, Spartan 6, Series 7, Ultrascale.
# Cell('FDCE'),
diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v
index 8ac596459..66b7c583f 100644
--- a/techlibs/xilinx/cells_xtra.v
+++ b/techlibs/xilinx/cells_xtra.v
@@ -17,27 +17,6 @@ module FDCPE (...);
input PRE;
endmodule
-module FDRSE (...);
- parameter [0:0] INIT = 1'b0;
- parameter [0:0] IS_C_INVERTED = 1'b0;
- parameter [0:0] IS_CE_INVERTED = 1'b0;
- parameter [0:0] IS_D_INVERTED = 1'b0;
- parameter [0:0] IS_R_INVERTED = 1'b0;
- parameter [0:0] IS_S_INVERTED = 1'b0;
- output Q;
- (* clkbuf_sink *)
- (* invertible_pin = "IS_C_INVERTED" *)
- input C;
- (* invertible_pin = "IS_CE_INVERTED" *)
- input CE;
- (* invertible_pin = "IS_D_INVERTED" *)
- input D;
- (* invertible_pin = "IS_R_INVERTED" *)
- input R;
- (* invertible_pin = "IS_S_INVERTED" *)
- input S;
-endmodule
-
module LDCPE (...);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_CLR_INVERTED = 1'b0;
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 2c5686a35..971089b28 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -444,6 +444,16 @@ struct SynthXilinxPass : public ScriptPass
}
if (check_label("map_ffram")) {
+ // Required for dffsr2dff to work.
+ run("simplemap t:$dff t:$adff t:$mux");
+ // Needs to be done before opt -mux_bool happens.
+ run("dffsr2dff");
+ if (help_mode)
+ run("dff2dffs [-match-init]", "(-match-init for xc6s only)");
+ else if (family == "xc6s")
+ run("dff2dffs -match-init");
+ else
+ run("dff2dffs");
if (widemux > 0)
run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover
// performs less efficiently
@@ -453,14 +463,11 @@ struct SynthXilinxPass : public ScriptPass
}
if (check_label("fine")) {
- run("dffsr2dff");
- run("dff2dffe");
+ run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
if (help_mode) {
- run("simplemap t:$mux", " ('-widemux' only)");
run("muxcover <internal options>, ('-widemux' only)");
}
else if (widemux > 0) {
- run("simplemap t:$mux");
constexpr int cost_mux2 = 100;
std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2);
switch (widemux) {
@@ -563,6 +570,7 @@ struct SynthXilinxPass : public ScriptPass
else
techmap_args += " -map " + ff_map_file;
run("techmap " + techmap_args);
+ run("xilinx_dffopt");
run("clean");
}
diff --git a/techlibs/xilinx/xc6s_ff_map.v b/techlibs/xilinx/xc6s_ff_map.v
index bf35b09e5..c40f446e0 100644
--- a/techlibs/xilinx/xc6s_ff_map.v
+++ b/techlibs/xilinx/xc6s_ff_map.v
@@ -27,6 +27,8 @@
`ifndef _NO_FFS
+// No reset.
+
module \$_DFF_N_ (input D, C, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@@ -46,6 +48,8 @@ module \$_DFF_P_ (input D, C, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+// No reset, enable.
+
module \$_DFFE_NP_ (input D, C, E, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@@ -65,80 +69,168 @@ module \$_DFFE_PP_ (input D, C, E, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NN0_ (input D, C, R, output Q);
+// Async reset.
+
+module \$_DFF_NP0_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
else
- FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
+ FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NP0_ (input D, C, R, output Q);
+module \$_DFF_PP0_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
else
- FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
+ FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PN0_ (input D, C, R, output Q);
+
+module \$_DFF_NP1_ (input D, C, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
+ $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
+ else
+ FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$_DFF_PP1_ (input D, C, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
+ $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
+ else
+ FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Async reset, enable.
+
+module \$__DFFE_NP0 (input D, C, E, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
else
- FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
+ FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PP0_ (input D, C, R, output Q);
+module \$__DFFE_PP0 (input D, C, E, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
else
- FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
+ FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NN1_ (input D, C, R, output Q);
+module \$__DFFE_NP1 (input D, C, E, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
$error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
else
- FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
+ FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NP1_ (input D, C, R, output Q);
+module \$__DFFE_PP1 (input D, C, E, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
$error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
else
- FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Sync reset.
+
+module \$__DFFS_NP0_ (input D, C, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
+ $error("Spartan 6 doesn't support FFs with reset initialized to 1");
+ else
+ FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PN1_ (input D, C, R, output Q);
+module \$__DFFS_PP0_ (input D, C, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
+ $error("Spartan 6 doesn't support FFs with reset initialized to 1");
+ else
+ FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+module \$__DFFS_NP1_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
- $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
+ $error("Spartan 6 doesn't support FFs with set initialized to 0");
else
- FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
+ FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PP1_ (input D, C, R, output Q);
+module \$__DFFS_PP1_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
- $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
+ $error("Spartan 6 doesn't support FFs with set initialized to 0");
else
- FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+// Sync reset, enable.
+
+module \$__DFFSE_NP0 (input D, C, E, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
+ $error("Spartan 6 doesn't support FFs with reset initialized to 1");
+ else
+ FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$__DFFSE_PP0 (input D, C, E, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
+ $error("Spartan 6 doesn't support FFs with reset initialized to 1");
+ else
+ FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+module \$__DFFSE_NP1 (input D, C, E, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
+ $error("Spartan 6 doesn't support FFs with set initialized to 0");
+ else
+ FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$__DFFSE_PP1 (input D, C, E, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
+ $error("Spartan 6 doesn't support FFs with set initialized to 0");
+ else
+ FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Latches (no reset).
+
module \$_DLATCH_N_ (input E, D, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@@ -158,5 +250,7 @@ module \$_DLATCH_P_ (input E, D, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+// Latches with reset (TODO).
+
`endif
diff --git a/techlibs/xilinx/xc7_ff_map.v b/techlibs/xilinx/xc7_ff_map.v
index 32ca9f560..2bd874457 100644
--- a/techlibs/xilinx/xc7_ff_map.v
+++ b/techlibs/xilinx/xc7_ff_map.v
@@ -37,6 +37,8 @@
`ifndef _NO_FFS
+// No reset.
+
module \$_DFF_N_ (input D, C, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0));
@@ -48,6 +50,8 @@ module \$_DFF_P_ (input D, C, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+// No reset, enable.
+
module \$_DFFE_NP_ (input D, C, E, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0));
@@ -59,47 +63,103 @@ module \$_DFFE_PP_ (input D, C, E, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NN0_ (input D, C, R, output Q);
+// Async reset.
+
+module \$_DFF_NP0_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
+ FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NP0_ (input D, C, R, output Q);
+module \$_DFF_PP0_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
+ FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PN0_ (input D, C, R, output Q);
+
+module \$_DFF_NP1_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
+ FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PP0_ (input D, C, R, output Q);
+module \$_DFF_PP1_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
+ FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NN1_ (input D, C, R, output Q);
+// Async reset, enable.
+
+module \$__DFFE_NP0 (input D, C, E, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
+ FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NP1_ (input D, C, R, output Q);
+module \$__DFFE_PP0 (input D, C, E, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PN1_ (input D, C, R, output Q);
+
+module \$__DFFE_NP1 (input D, C, E, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
+ FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PP1_ (input D, C, R, output Q);
+module \$__DFFE_PP1 (input D, C, E, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Sync reset.
+
+module \$__DFFS_NP0_ (input D, C, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+module \$__DFFS_PP0_ (input D, C, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+module \$__DFFS_NP1_ (input D, C, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$__DFFS_PP1_ (input D, C, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Sync reset, enable.
+
+module \$__DFFSE_NP0 (input D, C, E, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$__DFFSE_PP0 (input D, C, E, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+module \$__DFFSE_NP1 (input D, C, E, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$__DFFSE_PP1 (input D, C, E, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Latches (no reset).
module \$_DLATCH_N_ (input E, D, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
@@ -112,5 +172,7 @@ module \$_DLATCH_P_ (input E, D, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+// Latches with reset (TODO).
+
`endif
diff --git a/techlibs/xilinx/xilinx_dffopt.cc b/techlibs/xilinx/xilinx_dffopt.cc
new file mode 100644
index 000000000..1256a08cb
--- /dev/null
+++ b/techlibs/xilinx/xilinx_dffopt.cc
@@ -0,0 +1,351 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+typedef std::pair<Const, std::vector<SigBit>> LutData;
+
+// Compute a LUT implementing (select ^ select_inv) ? alt_data : data. Returns true if successful.
+bool merge_lut(LutData &result, const LutData &data, const LutData select, bool select_inv, SigBit alt_data, int max_lut_size) {
+ // First, gather input signals.
+ result.second = data.second;
+ int idx_alt = -1;
+ if (alt_data.wire) {
+ // Check if we already have it.
+ for (int i = 0; i < GetSize(result.second); i++)
+ if (result.second[i] == alt_data)
+ idx_alt = i;
+ // If not, add it.
+ if (idx_alt == -1) {
+ idx_alt = GetSize(result.second);
+ result.second.push_back(alt_data);
+ }
+ }
+ std::vector<int> idx_sel;
+ for (auto bit : select.second) {
+ int idx = -1;
+ for (int i = 0; i < GetSize(result.second); i++)
+ if (result.second[i] == bit)
+ idx = i;
+ if (idx == -1) {
+ idx = GetSize(result.second);
+ result.second.push_back(bit);
+ }
+ idx_sel.push_back(idx);
+ }
+
+ // If LUT would be too large, bail.
+ if (GetSize(result.second) > max_lut_size)
+ return false;
+
+ // Okay, we're doing it — compute the LUT mask.
+ result.first = Const(0, 1 << GetSize(result.second));
+ for (int i = 0; i < GetSize(result.first); i++) {
+ int sel_lut_idx = 0;
+ for (int j = 0; j < GetSize(select.second); j++)
+ if (i & 1 << idx_sel[j])
+ sel_lut_idx |= 1 << j;
+ bool select_val = (select.first.bits[sel_lut_idx] == State::S1);
+ bool new_bit;
+ if (select_val ^ select_inv) {
+ // Use alt_data.
+ if (alt_data.wire)
+ new_bit = (i & 1 << idx_alt) != 0;
+ else
+ new_bit = alt_data.data == State::S1;
+ } else {
+ // Use original LUT.
+ int lut_idx = i & ((1 << GetSize(data.second)) - 1);
+ new_bit = data.first.bits[lut_idx] == State::S1;
+ }
+ result.first.bits[i] = new_bit ? State::S1 : State::S0;
+ }
+ return true;
+}
+
+struct XilinxDffOptPass : public Pass {
+ XilinxDffOptPass() : Pass("xilinx_dffopt", "Xilinx: optimize FF control signal usage") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" xilinx_dffopt [options] [selection]\n");
+ log("\n");
+ log("Converts hardware clock enable and set/reset signals on FFs to emulation\n");
+ log("using LUTs, if doing so would improve area. Operates on post-techmap Xilinx\n");
+ log("cells (LUT*, FD*).\n");
+ log("\n");
+ log(" -lut4\n");
+ log(" Assume a LUT4-based device (instead of a LUT6-based device).\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing XILINX_DFFOPT pass (optimize FF control signal usage).\n");
+
+ size_t argidx;
+ int max_lut_size = 6;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-lut4") {
+ max_lut_size = 4;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ log("Optimizing FFs in %s.\n", log_id(module));
+
+ SigMap sigmap(module);
+ dict<SigBit, pair<LutData, Cell *>> bit_to_lut;
+ dict<SigBit, int> bit_uses;
+
+ // Gather LUTs.
+ for (auto cell : module->selected_cells())
+ {
+ for (auto port : cell->connections())
+ for (auto bit : port.second)
+ bit_uses[sigmap(bit)]++;
+ if (cell->get_bool_attribute(ID::keep))
+ continue;
+ if (cell->type == ID(INV)) {
+ SigBit sigout = sigmap(cell->getPort(ID(O)));
+ SigBit sigin = sigmap(cell->getPort(ID(I)));
+ bit_to_lut[sigout] = make_pair(LutData(Const(1, 2), {sigin}), cell);
+ } else if (cell->type.in(ID(LUT1), ID(LUT2), ID(LUT3), ID(LUT4), ID(LUT5), ID(LUT6))) {
+ SigBit sigout = sigmap(cell->getPort(ID(O)));
+ const Const &init = cell->getParam(ID(INIT));
+ std::vector<SigBit> sigin;
+ sigin.push_back(sigmap(cell->getPort(ID(I0))));
+ if (cell->type == ID(LUT1))
+ goto lut_sigin_done;
+ sigin.push_back(sigmap(cell->getPort(ID(I1))));
+ if (cell->type == ID(LUT2))
+ goto lut_sigin_done;
+ sigin.push_back(sigmap(cell->getPort(ID(I2))));
+ if (cell->type == ID(LUT3))
+ goto lut_sigin_done;
+ sigin.push_back(sigmap(cell->getPort(ID(I3))));
+ if (cell->type == ID(LUT4))
+ goto lut_sigin_done;
+ sigin.push_back(sigmap(cell->getPort(ID(I4))));
+ if (cell->type == ID(LUT5))
+ goto lut_sigin_done;
+ sigin.push_back(sigmap(cell->getPort(ID(I5))));
+lut_sigin_done:
+ bit_to_lut[sigout] = make_pair(LutData(init, sigin), cell);
+ }
+ }
+ for (auto wire : module->wires())
+ if (wire->port_output || wire->port_input)
+ for (int i = 0; i < GetSize(wire); i++)
+ bit_uses[sigmap(SigBit(wire, i))]++;
+
+ // Iterate through FFs.
+ for (auto cell : module->selected_cells())
+ {
+ bool has_s = false, has_r = false;
+ if (cell->type.in(ID(FDCE), ID(FDPE), ID(FDCPE), ID(FDCE_1), ID(FDPE_1), ID(FDCPE_1))) {
+ // Async reset.
+ } else if (cell->type.in(ID(FDRE), ID(FDRE_1))) {
+ has_r = true;
+ } else if (cell->type.in(ID(FDSE), ID(FDSE_1))) {
+ has_s = true;
+ } else if (cell->type.in(ID(FDRSE), ID(FDRSE_1))) {
+ has_r = true;
+ has_s = true;
+ } else {
+ // Not a FF.
+ continue;
+ }
+ if (cell->get_bool_attribute(ID::keep))
+ continue;
+
+ // Don't bother if D has more than one use.
+ SigBit sig_D = sigmap(cell->getPort(ID(D)));
+ if (bit_uses[sig_D] > 2)
+ continue;
+
+ // Find the D LUT.
+ auto it_D = bit_to_lut.find(sig_D);
+ if (it_D == bit_to_lut.end())
+ continue;
+ LutData lut_d = it_D->second.first;
+ Cell *cell_d = it_D->second.second;
+ if (cell->hasParam(ID(IS_D_INVERTED)) && cell->getParam(ID(IS_D_INVERTED)).as_bool()) {
+ // Flip all bits in the LUT.
+ for (int i = 0; i < GetSize(lut_d.first); i++)
+ lut_d.first.bits[i] = (lut_d.first.bits[i] == State::S1) ? State::S0 : State::S1;
+ }
+
+ LutData lut_d_post_ce;
+ LutData lut_d_post_s;
+ LutData lut_d_post_r;
+ bool worthy_post_ce = false;
+ bool worthy_post_s = false;
+ bool worthy_post_r = false;
+
+ // First, unmap CE.
+ SigBit sig_Q = sigmap(cell->getPort(ID(Q)));
+ SigBit sig_CE = sigmap(cell->getPort(ID(CE)));
+ LutData lut_ce = LutData(Const(2, 2), {sig_CE});
+ auto it_CE = bit_to_lut.find(sig_CE);
+ if (it_CE != bit_to_lut.end())
+ lut_ce = it_CE->second.first;
+ if (sig_CE.wire) {
+ // Merge CE LUT and D LUT into one. If it cannot be done, nothing to do about this FF.
+ if (!merge_lut(lut_d_post_ce, lut_d, lut_ce, true, sig_Q, max_lut_size))
+ continue;
+
+ // If this gets rid of a CE LUT, it's worth it. If not, it still may be worth it, if we can remove set/reset as well.
+ if (it_CE != bit_to_lut.end())
+ worthy_post_ce = true;
+ } else if (sig_CE.data != State::S1) {
+ // Strange. Should not happen in a reasonable flow, so bail.
+ continue;
+ } else {
+ lut_d_post_ce = lut_d;
+ }
+
+ // Second, unmap S, if any.
+ lut_d_post_s = lut_d_post_ce;
+ if (has_s) {
+ SigBit sig_S = sigmap(cell->getPort(ID(S)));
+ LutData lut_s = LutData(Const(2, 2), {sig_S});
+ bool inv_s = cell->hasParam(ID(IS_S_INVERTED)) && cell->getParam(ID(IS_S_INVERTED)).as_bool();
+ auto it_S = bit_to_lut.find(sig_S);
+ if (it_S != bit_to_lut.end())
+ lut_s = it_S->second.first;
+ if (sig_S.wire) {
+ // Merge S LUT and D LUT into one. If it cannot be done, try to at least merge CE.
+ if (!merge_lut(lut_d_post_s, lut_d_post_ce, lut_s, inv_s, SigBit(State::S1), max_lut_size))
+ goto unmap;
+ // If this gets rid of an S LUT, it's worth it.
+ if (it_S != bit_to_lut.end())
+ worthy_post_s = true;
+ } else if (sig_S.data != (inv_s ? State::S1 : State::S0)) {
+ // Strange. Should not happen in a reasonable flow, so bail.
+ continue;
+ }
+ }
+
+ // Third, unmap R, if any.
+ lut_d_post_r = lut_d_post_s;
+ if (has_r) {
+ SigBit sig_R = sigmap(cell->getPort(ID(R)));
+ LutData lut_r = LutData(Const(2, 2), {sig_R});
+ bool inv_r = cell->hasParam(ID(IS_R_INVERTED)) && cell->getParam(ID(IS_R_INVERTED)).as_bool();
+ auto it_R = bit_to_lut.find(sig_R);
+ if (it_R != bit_to_lut.end())
+ lut_r = it_R->second.first;
+ if (sig_R.wire) {
+ // Merge R LUT and D LUT into one. If it cannot be done, try to at least merge CE/S.
+ if (!merge_lut(lut_d_post_r, lut_d_post_s, lut_r, inv_r, SigBit(State::S0), max_lut_size))
+ goto unmap;
+ // If this gets rid of an S LUT, it's worth it.
+ if (it_R != bit_to_lut.end())
+ worthy_post_r = true;
+ } else if (sig_R.data != (inv_r ? State::S1 : State::S0)) {
+ // Strange. Should not happen in a reasonable flow, so bail.
+ continue;
+ }
+ }
+
+unmap:
+ LutData final_lut;
+ if (worthy_post_r) {
+ final_lut = lut_d_post_r;
+ log(" Merging R LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second));
+ } else if (worthy_post_s) {
+ final_lut = lut_d_post_s;
+ log(" Merging S LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second));
+ } else if (worthy_post_ce) {
+ final_lut = lut_d_post_ce;
+ log(" Merging CE LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second));
+ } else {
+ // Nothing to do here.
+ continue;
+ }
+
+ // Okay, we're doing it. Unmap ports.
+ if (worthy_post_r) {
+ cell->unsetParam(ID(IS_R_INVERTED));
+ cell->setPort(ID(R), Const(0, 1));
+ }
+ if (has_s && (worthy_post_r || worthy_post_s)) {
+ cell->unsetParam(ID(IS_S_INVERTED));
+ cell->setPort(ID(S), Const(0, 1));
+ }
+ cell->setPort(ID(CE), Const(1, 1));
+ cell->unsetParam(ID(IS_D_INVERTED));
+
+ // Create the new LUT.
+ Cell *lut_cell = 0;
+ switch (GetSize(final_lut.second)) {
+ case 1:
+ lut_cell = module->addCell(NEW_ID, ID(LUT1));
+ break;
+ case 2:
+ lut_cell = module->addCell(NEW_ID, ID(LUT2));
+ break;
+ case 3:
+ lut_cell = module->addCell(NEW_ID, ID(LUT3));
+ break;
+ case 4:
+ lut_cell = module->addCell(NEW_ID, ID(LUT4));
+ break;
+ case 5:
+ lut_cell = module->addCell(NEW_ID, ID(LUT5));
+ break;
+ case 6:
+ lut_cell = module->addCell(NEW_ID, ID(LUT6));
+ break;
+ default:
+ log_assert(!"unknown lut size");
+ }
+ lut_cell->attributes = cell_d->attributes;
+ Wire *lut_out = module->addWire(NEW_ID);
+ lut_cell->setParam(ID(INIT), final_lut.first);
+ cell->setPort(ID(D), lut_out);
+ lut_cell->setPort(ID(O), lut_out);
+ lut_cell->setPort(ID(I0), final_lut.second[0]);
+ if (GetSize(final_lut.second) >= 2)
+ lut_cell->setPort(ID(I1), final_lut.second[1]);
+ if (GetSize(final_lut.second) >= 3)
+ lut_cell->setPort(ID(I2), final_lut.second[2]);
+ if (GetSize(final_lut.second) >= 4)
+ lut_cell->setPort(ID(I3), final_lut.second[3]);
+ if (GetSize(final_lut.second) >= 5)
+ lut_cell->setPort(ID(I4), final_lut.second[4]);
+ if (GetSize(final_lut.second) >= 6)
+ lut_cell->setPort(ID(I5), final_lut.second[5]);
+ }
+ }
+ }
+} XilinxDffOptPass;
+
+PRIVATE_NAMESPACE_END
+