dfflegalize: Refactor, add aldff support.
authorMarcelina Kościelnicka <mwk@0x04.net>
Wed, 27 Oct 2021 08:14:07 +0000 (10:14 +0200)
committerMarcelina Kościelnicka <mwk@0x04.net>
Wed, 27 Oct 2021 12:14:01 +0000 (14:14 +0200)
12 files changed:
kernel/ff.cc
kernel/ff.h
passes/techmap/dfflegalize.cc
tests/techmap/dfflegalize_adff_init.ys
tests/techmap/dfflegalize_adlatch_init.ys
tests/techmap/dfflegalize_dff.ys
tests/techmap/dfflegalize_dff_init.ys
tests/techmap/dfflegalize_dlatch_const.ys
tests/techmap/dfflegalize_dlatchsr_init.ys
tests/techmap/dfflegalize_minsrst.ys
tests/techmap/dfflegalize_sr.ys
tests/techmap/dfflegalize_sr_init.ys

index c2f1a75a023474834f629bf070f48ab9a317465b..c43482bd242e2c127114f68627a9f9292901600a 100644 (file)
@@ -303,6 +303,190 @@ FfData FfData::slice(const std::vector<int> &bits) {
        return res;
 }
 
+void FfData::add_dummy_ce() {
+       if (has_ce)
+               return;
+       has_ce = true;
+       pol_ce = true;
+       sig_ce = State::S1;
+       ce_over_srst = false;
+}
+
+void FfData::add_dummy_srst() {
+       if (has_srst)
+               return;
+       has_srst = true;
+       pol_srst = true;
+       sig_srst = State::S0;
+       val_srst = Const(State::Sx, width);
+       ce_over_srst = false;
+}
+
+void FfData::add_dummy_arst() {
+       if (has_arst)
+               return;
+       has_arst = true;
+       pol_arst = true;
+       sig_arst = State::S0;
+       val_arst = Const(State::Sx, width);
+}
+
+void FfData::add_dummy_aload() {
+       if (has_aload)
+               return;
+       has_aload = true;
+       pol_aload = true;
+       sig_aload = State::S0;
+       sig_ad = Const(State::Sx, width);
+}
+
+void FfData::add_dummy_sr() {
+       if (has_sr)
+               return;
+       has_sr = true;
+       pol_clr = true;
+       pol_set = true;
+       sig_clr = Const(State::S0, width);
+       sig_set = Const(State::S0, width);
+}
+
+void FfData::add_dummy_clk() {
+       if (has_clk)
+               return;
+       has_clk = true;
+       pol_clk = true;
+       sig_clk = State::S0;
+       sig_d = Const(State::Sx, width);
+}
+
+void FfData::arst_to_aload() {
+       log_assert(has_arst);
+       log_assert(!has_aload);
+       pol_aload = pol_arst;
+       sig_aload = sig_arst;
+       sig_ad = val_arst;
+       has_aload = true;
+       has_arst = false;
+}
+
+void FfData::arst_to_sr() {
+       log_assert(has_arst);
+       log_assert(!has_sr);
+       pol_clr = pol_arst;
+       pol_set = pol_arst;
+       sig_clr = Const(pol_arst ? State::S0 : State::S1, width);
+       sig_set = Const(pol_arst ? State::S0 : State::S1, width);
+       has_sr = true;
+       has_arst = false;
+       for (int i = 0; i < width; i++) {
+               if (val_arst[i] == State::S1)
+                       sig_set[i] = sig_arst;
+               else
+                       sig_clr[i] = sig_arst;
+       }
+}
+
+void FfData::aload_to_sr() {
+       log_assert(has_aload);
+       log_assert(!has_sr);
+       has_sr = true;
+       has_aload = false;
+       if (!is_fine) {
+               pol_clr = false;
+               pol_set = true;
+               if (pol_aload) {
+                       sig_clr = module->Mux(NEW_ID, Const(State::S1, width), sig_ad, sig_aload);
+                       sig_set = module->Mux(NEW_ID, Const(State::S0, width), sig_ad, sig_aload);
+               } else {
+                       sig_clr = module->Mux(NEW_ID, sig_ad, Const(State::S1, width), sig_aload);
+                       sig_set = module->Mux(NEW_ID, sig_ad, Const(State::S0, width), sig_aload);
+               }
+       } else {
+               pol_clr = pol_aload;
+               pol_set = pol_aload;
+               if (pol_aload) {
+                       sig_clr = module->AndnotGate(NEW_ID, sig_aload, sig_ad);
+                       sig_set = module->AndGate(NEW_ID, sig_aload, sig_ad);
+               } else {
+                       sig_clr = module->OrGate(NEW_ID, sig_aload, sig_ad);
+                       sig_set = module->OrnotGate(NEW_ID, sig_aload, sig_ad);
+               }
+       }
+}
+
+void FfData::convert_ce_over_srst(bool val) {
+       if (!has_ce || !has_srst || ce_over_srst == val)
+               return;
+       if (val) {
+               // sdffe to sdffce
+               if (!is_fine) {
+                       if (pol_ce) {
+                               if (pol_srst) {
+                                       sig_ce = module->Or(NEW_ID, sig_ce, sig_srst);
+                               } else {
+                                       SigSpec tmp = module->Not(NEW_ID, sig_srst);
+                                       sig_ce = module->Or(NEW_ID, sig_ce, tmp);
+                               }
+                       } else {
+                               if (pol_srst) {
+                                       SigSpec tmp = module->Not(NEW_ID, sig_srst);
+                                       sig_ce = module->And(NEW_ID, sig_ce, tmp);
+                               } else {
+                                       sig_ce = module->And(NEW_ID, sig_ce, sig_srst);
+                               }
+                       }
+               } else {
+                       if (pol_ce) {
+                               if (pol_srst) {
+                                       sig_ce = module->OrGate(NEW_ID, sig_ce, sig_srst);
+                               } else {
+                                       sig_ce = module->OrnotGate(NEW_ID, sig_ce, sig_srst);
+                               }
+                       } else {
+                               if (pol_srst) {
+                                       sig_ce = module->AndnotGate(NEW_ID, sig_ce, sig_srst);
+                               } else {
+                                       sig_ce = module->AndGate(NEW_ID, sig_ce, sig_srst);
+                               }
+                       }
+               }
+       } else {
+               // sdffce to sdffe
+               if (!is_fine) {
+                       if (pol_srst) {
+                               if (pol_ce) {
+                                       sig_srst = cell->module->And(NEW_ID, sig_srst, sig_ce);
+                               } else {
+                                       SigSpec tmp = module->Not(NEW_ID, sig_ce);
+                                       sig_srst = cell->module->And(NEW_ID, sig_srst, tmp);
+                               }
+                       } else {
+                               if (pol_ce) {
+                                       SigSpec tmp = module->Not(NEW_ID, sig_ce);
+                                       sig_srst = cell->module->Or(NEW_ID, sig_srst, tmp);
+                               } else {
+                                       sig_srst = cell->module->Or(NEW_ID, sig_srst, sig_ce);
+                               }
+                       }
+               } else {
+                       if (pol_srst) {
+                               if (pol_ce) {
+                                       sig_srst = cell->module->AndGate(NEW_ID, sig_srst, sig_ce);
+                               } else {
+                                       sig_srst = cell->module->AndnotGate(NEW_ID, sig_srst, sig_ce);
+                               }
+                       } else {
+                               if (pol_ce) {
+                                       sig_srst = cell->module->OrnotGate(NEW_ID, sig_srst, sig_ce);
+                               } else {
+                                       sig_srst = cell->module->OrGate(NEW_ID, sig_srst, sig_ce);
+                               }
+                       }
+               }
+       }
+       ce_over_srst = val;
+}
+
 void FfData::unmap_ce() {
        if (!has_ce)
                return;
@@ -351,11 +535,7 @@ Cell *FfData::emit() {
        if (!has_aload && !has_clk && !has_gclk && !has_sr) {
                if (has_arst) {
                        // Convert this case to a D latch.
-                       has_aload = true;
-                       has_arst = false;
-                       sig_ad = val_arst;
-                       sig_aload = sig_arst;
-                       pol_aload = pol_arst;
+                       arst_to_aload();
                } else {
                        // No control inputs left.  Turn into a const driver.
                        module->connect(sig_q, val_init);
@@ -506,7 +686,7 @@ void FfData::flip_bits(const pool<int> &bits) {
        }
 
        if (has_sr && cell) {
-               log_warning("Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s].", log_id(module->name), log_id(cell->name), log_id(cell->type));
+               log_warning("Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s].\n", log_id(module->name), log_id(cell->name), log_id(cell->type));
        }
 
        if (is_fine) {
index 3125f67c698fb4220542e9aaeace964d4e82b8f9..5a629d5dd6c18d7aaebf2ada572f87ad81d15514 100644 (file)
@@ -170,8 +170,23 @@ struct FfData {
        // Returns a FF identical to this one, but only keeping bit indices from the argument.
        FfData slice(const std::vector<int> &bits);
 
-       void unmap_ce();
+       void add_dummy_ce();
+       void add_dummy_srst();
+       void add_dummy_arst();
+       void add_dummy_aload();
+       void add_dummy_sr();
+       void add_dummy_clk();
+
+       void arst_to_aload();
+       void arst_to_sr();
+
+       void aload_to_sr();
 
+       // Given a FF with both has_ce and has_srst, sets ce_over_srst to the given value and
+       // fixes up control signals appropriately to preserve semantics.
+       void convert_ce_over_srst(bool val);
+
+       void unmap_ce();
        void unmap_srst();
 
        void unmap_ce_srst() {
index 5210d01eb9814f3b73368d6e8ad255b3d61f2346..1d99caa3a54f1b498a3cbee7a26734e53f1a5f04 100644 (file)
@@ -20,6 +20,7 @@
 #include "kernel/yosys.h"
 #include "kernel/sigtools.h"
 #include "kernel/ffinit.h"
+#include "kernel/ff.h"
 
 USING_YOSYS_NAMESPACE
 PRIVATE_NAMESPACE_BEGIN
@@ -27,38 +28,42 @@ PRIVATE_NAMESPACE_BEGIN
 enum FfType {
        FF_DFF,
        FF_DFFE,
-       FF_ADFF0,
-       FF_ADFF1,
-       FF_ADFFE0,
-       FF_ADFFE1,
+       FF_ADFF,
+       FF_ADFFE,
+       FF_ALDFF,
+       FF_ALDFFE,
        FF_DFFSR,
        FF_DFFSRE,
-       FF_SDFF0,
-       FF_SDFF1,
-       FF_SDFFE0,
-       FF_SDFFE1,
-       FF_SDFFCE0,
-       FF_SDFFCE1,
+       FF_SDFF,
+       FF_SDFFE,
+       FF_SDFFCE,
+       FF_RLATCH,
        FF_SR,
        FF_DLATCH,
-       FF_ADLATCH0,
-       FF_ADLATCH1,
+       FF_ADLATCH,
        FF_DLATCHSR,
        NUM_FFTYPES,
 };
 
 enum FfNeg {
-       NEG_R = 0x1,
-       NEG_S = 0x2,
-       NEG_E = 0x4,
-       NEG_C = 0x8,
-       NUM_NEG = 0x10,
+       NEG_CE = 0x1,
+       NEG_R = 0x2,
+       NEG_S = 0x4,
+       NEG_L = 0x8,
+       NEG_C = 0x10,
+       NUM_NEG = 0x20,
 };
 
 enum FfInit {
        INIT_X = 0x1,
        INIT_0 = 0x2,
        INIT_1 = 0x4,
+       INIT_X_R0 = 0x10,
+       INIT_0_R0 = 0x20,
+       INIT_1_R0 = 0x40,
+       INIT_X_R1 = 0x100,
+       INIT_0_R1 = 0x200,
+       INIT_1_R1 = 0x400,
 };
 
 struct DffLegalizePass : public Pass {
@@ -101,6 +106,8 @@ struct DffLegalizePass : public Pass {
                log("- $_DFFE_[NP][NP]_\n");
                log("- $_DFF_[NP][NP][01]_\n");
                log("- $_DFFE_[NP][NP][01][NP]_\n");
+               log("- $_ALDFF_[NP][NP]_\n");
+               log("- $_ALDFFE_[NP][NP][NP]_\n");
                log("- $_DFFSR_[NP][NP][NP]_\n");
                log("- $_DFFSRE_[NP][NP][NP][NP]_\n");
                log("- $_SDFF_[NP][NP][01]_\n");
@@ -151,18 +158,30 @@ struct DffLegalizePass : public Pass {
        int supported_cells[NUM_FFTYPES];
        // Aggregated for all *dff* cells.
        int supported_dff;
+       // Aggregated for all *dffe* cells.
+       int supported_dffe;
        // Aggregated for all dffsr* cells.
        int supported_dffsr;
-       // Aggregated for all adff* cells.
-       int supported_adff0;
-       int supported_adff1;
+       // Aggregated for all aldff cells.
+       int supported_aldff;
+       // Aggregated for all aldffe cells.
+       int supported_aldffe;
+       // Aggregated for all adff* cells and trivial emulations.
+       int supported_adff;
+       // Aggregated for all adffe* cells and trivial emulations.
+       int supported_adffe;
        // Aggregated for all sdff* cells.
-       int supported_sdff0;
-       int supported_sdff1;
+       int supported_sdff;
        // Aggregated for all ways to obtain a SR latch.
        int supported_sr;
+       int supported_sr_plain;
        // Aggregated for all *dlatch* cells.
        int supported_dlatch;
+       int supported_dlatch_plain;
+       // Aggregated for all ways to obtain an R latch.
+       int supported_rlatch;
+       // Aggregated for all adlatch cells and trivial emulations.
+       int supported_adlatch;
 
        int mince;
        int minsrst;
@@ -179,732 +198,794 @@ struct DffLegalizePass : public Pass {
                        res |= INIT_1;
                if (mask & INIT_1)
                        res |= INIT_0;
+               if (mask & INIT_X_R0)
+                       res |= INIT_X_R1;
+               if (mask & INIT_0_R0)
+                       res |= INIT_1_R1;
+               if (mask & INIT_1_R0)
+                       res |= INIT_0_R1;
+               if (mask & INIT_X_R1)
+                       res |= INIT_X_R0;
+               if (mask & INIT_0_R1)
+                       res |= INIT_1_R0;
+               if (mask & INIT_1_R1)
+                       res |= INIT_0_R0;
                return res;
        }
 
-       void handle_ff(Cell *cell) {
-               std::string type_str = cell->type.str();
-
-               FfType ff_type;
-               int ff_neg = 0;
-               SigSpec sig_d;
-               SigSpec sig_q;
-               SigSpec sig_c;
-               SigSpec sig_e;
-               SigSpec sig_r;
-               SigSpec sig_s;
-               bool has_srst = false;
-
-               if (cell->hasPort(ID::D))
-                       sig_d = cell->getPort(ID::D);
-               if (cell->hasPort(ID::Q))
-                       sig_q = cell->getPort(ID::Q);
-               if (cell->hasPort(ID::C))
-                       sig_c = cell->getPort(ID::C);
-               if (cell->hasPort(ID::E))
-                       sig_e = cell->getPort(ID::E);
-               if (cell->hasPort(ID::R))
-                       sig_r = cell->getPort(ID::R);
-               if (cell->hasPort(ID::S))
-                       sig_s = cell->getPort(ID::S);
-               
-               if (type_str.substr(0, 5) == "$_SR_") {
-                       ff_type = FF_SR;
-                       if (type_str[5] == 'N')
-                               ff_neg |= NEG_S;
-                       if (type_str[6] == 'N')
-                               ff_neg |= NEG_R;
-               } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
-                       ff_type = FF_DFF;
-                       if (type_str[6] == 'N')
-                               ff_neg |= NEG_C;
-               } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
-                       ff_type = FF_DFFE;
-                       if (type_str[7] == 'N')
-                               ff_neg |= NEG_C;
-                       if (type_str[8] == 'N')
-                               ff_neg |= NEG_E;
-               } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
-                       ff_type = type_str[8] == '1' ? FF_ADFF1 : FF_ADFF0;
-                       if (type_str[6] == 'N')
-                               ff_neg |= NEG_C;
-                       if (type_str[7] == 'N')
-                               ff_neg |= NEG_R;
-               } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
-                       ff_type = type_str[9] == '1' ? FF_ADFFE1 : FF_ADFFE0;
-                       if (type_str[7] == 'N')
-                               ff_neg |= NEG_C;
-                       if (type_str[8] == 'N')
-                               ff_neg |= NEG_R;
-                       if (type_str[10] == 'N')
-                               ff_neg |= NEG_E;
-               } else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
-                       ff_type = FF_DFFSR;
-                       if (type_str[8] == 'N')
-                               ff_neg |= NEG_C;
-                       if (type_str[9] == 'N')
-                               ff_neg |= NEG_S;
-                       if (type_str[10] == 'N')
-                               ff_neg |= NEG_R;
-               } else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
-                       ff_type = FF_DFFSRE;
-                       if (type_str[9] == 'N')
-                               ff_neg |= NEG_C;
-                       if (type_str[10] == 'N')
-                               ff_neg |= NEG_S;
-                       if (type_str[11] == 'N')
-                               ff_neg |= NEG_R;
-                       if (type_str[12] == 'N')
-                               ff_neg |= NEG_E;
-               } else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
-                       ff_type = type_str[9] == '1' ? FF_SDFF1 : FF_SDFF0;
-                       if (type_str[7] == 'N')
-                               ff_neg |= NEG_C;
-                       if (type_str[8] == 'N')
-                               ff_neg |= NEG_R;
-                       has_srst = true;
-               } else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
-                       ff_type = type_str[10] == '1' ? FF_SDFFE1 : FF_SDFFE0;
-                       if (type_str[8] == 'N')
-                               ff_neg |= NEG_C;
-                       if (type_str[9] == 'N')
-                               ff_neg |= NEG_R;
-                       if (type_str[11] == 'N')
-                               ff_neg |= NEG_E;
-                       has_srst = true;
-               } else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
-                       ff_type = type_str[11] == '1' ? FF_SDFFCE1 : FF_SDFFCE0;
-                       if (type_str[9] == 'N')
-                               ff_neg |= NEG_C;
-                       if (type_str[10] == 'N')
-                               ff_neg |= NEG_R;
-                       if (type_str[12] == 'N')
-                               ff_neg |= NEG_E;
-                       has_srst = true;
-               } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
-                       ff_type = FF_DLATCH;
-                       if (type_str[9] == 'N')
-                               ff_neg |= NEG_E;
-               } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
-                       ff_type = type_str[11] == '1' ? FF_ADLATCH1 : FF_ADLATCH0;
-                       if (type_str[9] == 'N')
-                               ff_neg |= NEG_E;
-                       if (type_str[10] == 'N')
-                               ff_neg |= NEG_R;
-               } else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
-                       ff_type = FF_DLATCHSR;
-                       if (type_str[11] == 'N')
-                               ff_neg |= NEG_E;
-                       if (type_str[12] == 'N')
-                               ff_neg |= NEG_S;
-                       if (type_str[13] == 'N')
-                               ff_neg |= NEG_R;
+       int get_ff_type(const FfData &ff) {
+               if (ff.has_clk) {
+                       if (ff.has_sr) {
+                               return ff.has_ce ? FF_DFFSRE : FF_DFFSR;
+                       } else if (ff.has_arst) {
+                               return ff.has_ce ? FF_ADFFE : FF_ADFF;
+                       } else if (ff.has_aload) {
+                               return ff.has_ce ? FF_ALDFFE : FF_ALDFF;
+                       } else if (ff.has_srst) {
+                               if (ff.has_ce)
+                                       return ff.ce_over_srst ? FF_SDFFCE : FF_SDFFE;
+                               else
+                                       return FF_SDFF;
+                       } else {
+                               return ff.has_ce ? FF_DFFE : FF_DFF;
+                       }
                } else {
-                       log_warning("Ignoring unknown ff type %s [%s.%s].\n", log_id(cell->type), log_id(cell->module->name), log_id(cell->name));
-                       return;
+                       if (ff.has_aload) {
+                               if (ff.has_sr)
+                                       return FF_DLATCHSR;
+                               else if (ff.has_arst)
+                                       return FF_ADLATCH;
+                               else
+                                       return FF_DLATCH;
+                       } else {
+                               if (ff.has_sr) {
+                                       return FF_SR;
+                               } else if (ff.has_arst) {
+                                       return FF_RLATCH;
+                               } else {
+                                       log_assert(0);
+                                       return 0;
+                               }
+                       }
                }
+       }
 
-               State initval = initvals(sig_q[0]);
-               
-               FfInit initmask = INIT_X;
-               if (initval == State::S0)
-                       initmask = INIT_0;
-               else if (initval == State::S1)
-                       initmask = INIT_1;
-               const char *reason;
+       int get_initmask(FfData &ff) {
+               int res = 0;
+               if (ff.val_init[0] == State::S0)
+                       res = INIT_0;
+               else if (ff.val_init[0] == State::S1)
+                       res = INIT_1;
+               else
+                       res = INIT_X;
+               if (ff.has_arst) {
+                       if (ff.val_arst[0] == State::S0)
+                               res <<= 4;
+                       else if (ff.val_arst[0] == State::S1)
+                               res <<= 8;
+               } else if (ff.has_srst) {
+                       if (ff.val_srst[0] == State::S0)
+                               res <<= 4;
+                       else if (ff.val_srst[0] == State::S1)
+                               res <<= 8;
+               }
+               return res;
+       }
 
-               bool kill_ce = mince && GetSize(sig_c) && GetSize(sig_e) && sig_e[0].wire && ce_used[sig_e[0]] < mince;
-               bool kill_srst = minsrst && has_srst && sig_r[0].wire && srst_used[sig_r[0]] < minsrst;
+       void fail_ff(const FfData &ff, const char *reason) {
+               log_error("FF %s.%s (type %s) cannot be legalized: %s\n", log_id(ff.module->name), log_id(ff.cell->name), log_id(ff.cell->type), reason);
+       }
 
-               while (!(supported_cells[ff_type] & initmask) || kill_ce || kill_srst) {
-                       // Well, cell is not directly supported.  Decide how to deal with it.
+       bool try_flip(FfData &ff, int supported_mask) {
+               int initmask = get_initmask(ff);
+               if (supported_mask & initmask)
+                       return true;
+               if (supported_mask & flip_initmask(initmask)) {
+                       ff.flip_bits({0});
+                       return true;
+               }
+               return false;
+       }
 
-                       if (ff_type == FF_DFF || ff_type == FF_DFFE) {
-                               if (kill_ce) {
-                                       ff_type = FF_DFF;
-                                       goto unmap_enable;
-                               }
-                               if (!(supported_dff & initmask)) {
-                                       // This init value is not supported at all...
-                                       if (supported_dff & flip_initmask(initmask)) {
-                                               // The other one is, though.  Negate D, Q, and init.
-flip_dqi:
-                                               if (initval == State::S0) {
-                                                       initval = State::S1;
-                                                       initmask = INIT_1;
-                                               } else if (initval == State::S1) {
-                                                       initval = State::S0;
-                                                       initmask = INIT_0;
-                                               }
-                                               if (ff_type != FF_SR)
-                                                       sig_d = cell->module->NotGate(NEW_ID, sig_d[0]);
-                                               SigBit new_q = SigSpec(cell->module->addWire(NEW_ID))[0];
-                                               cell->module->addNotGate(NEW_ID, new_q, sig_q[0]);
-                                               initvals.remove_init(sig_q[0]);
-                                               initvals.set_init(new_q, initval);
-                                               sig_q = new_q;
-                                               continue;
-                                       }
-                                       if (!supported_dff)
-                                               reason = "dffs are not supported";
-                                       else
-                                               reason = "initialized dffs are not supported";
-                                       goto error;
-                               }
+       void emulate_split_init_arst(FfData &ff) {
+               ff.remove();
 
-                               // Some DFF is supported with this init val.  Just pick a type.
-                               if (ff_type == FF_DFF) {
-                                       // Try adding a set or reset pin.
-                                       for (auto new_type: {FF_SDFF0, FF_SDFF1, FF_ADFF0, FF_ADFF1})
-                                               if (supported_cells[new_type] & initmask) {
-                                                       ff_type = new_type;
-                                                       sig_r = State::S0;
-                                                       goto cell_ok;
-                                               }
-                                       // Try adding both.
-                                       if (supported_cells[FF_DFFSR] & initmask) {
-                                               ff_type = FF_DFFSR;
-                                               sig_r = State::S0;
-                                               sig_s = State::S0;
-                                               break;
-                                       }
-                                       // Nope.  Will need to add enable and go the DFFE route.
-                                       sig_e = State::S1;
-                                       if (supported_cells[FF_DFFE] & initmask) {
-                                               ff_type = FF_DFFE;
-                                               break;
-                                       }
-                               }
-                               // Try adding a set or reset pin.
-                               for (auto new_type: {FF_SDFFE0, FF_SDFFE1, FF_SDFFCE0, FF_SDFFCE1, FF_ADFFE0, FF_ADFFE1})
-                                       if (supported_cells[new_type] & initmask) {
-                                               ff_type = new_type;
-                                               sig_r = State::S0;
-                                               goto cell_ok;
-                                       }
-                               // Try adding both.
-                               if (supported_cells[FF_DFFSRE] & initmask) {
-                                       ff_type = FF_DFFSRE;
-                                       sig_r = State::S0;
-                                       sig_s = State::S0;
-                                       break;
-                               }
+               FfData ff_dff(ff.module, &initvals, NEW_ID);
+               ff_dff.width = ff.width;
+               ff_dff.has_aload = ff.has_aload;
+               ff_dff.sig_aload = ff.sig_aload;
+               ff_dff.pol_aload = ff.pol_aload;
+               ff_dff.sig_ad = ff.sig_ad;
+               ff_dff.has_clk = ff.has_clk;
+               ff_dff.sig_clk = ff.sig_clk;
+               ff_dff.pol_clk = ff.pol_clk;
+               ff_dff.sig_d = ff.sig_d;
+               ff_dff.has_ce = ff.has_ce;
+               ff_dff.sig_ce = ff.sig_ce;
+               ff_dff.pol_ce = ff.pol_ce;
+               ff_dff.sig_q = ff.module->addWire(NEW_ID, ff.width);
+               ff_dff.val_init = ff.val_init;
+               ff_dff.is_fine = ff.is_fine;
+
+               FfData ff_adff(ff.module, &initvals, NEW_ID);
+               ff_adff.width = ff.width;
+               ff_adff.has_aload = ff.has_aload;
+               ff_adff.sig_aload = ff.sig_aload;
+               ff_adff.pol_aload = ff.pol_aload;
+               ff_adff.sig_ad = ff.sig_ad;
+               ff_adff.has_clk = ff.has_clk;
+               ff_adff.sig_clk = ff.sig_clk;
+               ff_adff.pol_clk = ff.pol_clk;
+               ff_adff.sig_d = ff.sig_d;
+               ff_adff.has_ce = ff.has_ce;
+               ff_adff.sig_ce = ff.sig_ce;
+               ff_adff.pol_ce = ff.pol_ce;
+               ff_adff.sig_q = ff.module->addWire(NEW_ID, ff.width);
+               ff_adff.val_init = Const(State::Sx, ff.width);
+               ff_adff.has_arst = true;
+               ff_adff.sig_arst = ff.sig_arst;
+               ff_adff.pol_arst = ff.pol_arst;
+               ff_adff.val_arst = ff.val_arst;
+               ff_adff.is_fine = ff.is_fine;
+
+               FfData ff_sel(ff.module, &initvals, NEW_ID);
+               ff_sel.width = 1;
+               ff_sel.sig_q = ff.module->addWire(NEW_ID);
+               ff_sel.has_arst = true;
+               ff_sel.sig_arst = ff.sig_arst;
+               ff_sel.pol_arst = ff.pol_arst;
+               ff_sel.val_arst = State::S1;
+               ff_sel.val_init = State::S0;
+               ff_sel.is_fine = ff.is_fine;
 
-                               // Seems that no DFFs with enable are supported.
-                               // The enable input needs to be unmapped.
-                               // This should not be reached if we started from plain DFF.
-                               log_assert(ff_type == FF_DFFE);
-                               ff_type = FF_DFF;
-unmap_enable:
-                               if (ff_neg & NEG_E)
-                                       sig_d = cell->module->MuxGate(NEW_ID, sig_d[0], sig_q[0], sig_e[0]);
+               if (ff.is_fine)
+                       ff.module->addMuxGate(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q);
+               else
+                       ff.module->addMux(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q);
+
+               legalize_ff(ff_dff);
+               legalize_ff(ff_adff);
+               legalize_ff(ff_sel);
+       }
+
+       void emulate_split_set_clr(FfData &ff) {
+               // No native DFFSR.  However, if we can conjure
+               // a SR latch and ADFF, it can still be emulated.
+               int initmask = get_initmask(ff);
+               int flipmask = flip_initmask(initmask);
+               bool init_clr = true;
+               bool init_set = true;
+               State initsel = State::Sx;
+               int supported_arst = ff.has_clk ? supported_adff : supported_adlatch;
+               bool init_clr_ok = (supported_arst & initmask << 4) || (supported_arst & flipmask << 8);
+               bool init_set_ok = (supported_arst & initmask << 8) || (supported_arst & flipmask << 4);
+               if (init_clr_ok && init_set_ok && supported_sr) {
+                       // OK
+               } else if (init_clr_ok && (supported_sr & INIT_0)) {
+                       init_set = false;
+                       initsel = State::S0;
+               } else if (init_set_ok && (supported_sr & INIT_1)) {
+                       init_clr = false;
+                       initsel = State::S1;
+               } else if (init_clr_ok && (supported_sr & INIT_1)) {
+                       init_set = false;
+                       initsel = State::S0;
+               } else if (init_set_ok && (supported_sr & INIT_0)) {
+                       init_clr = false;
+                       initsel = State::S1;
+               } else {
+                       if (ff.has_clk) {
+                               if (!supported_dffsr)
+                                       fail_ff(ff, "dffs with async set and reset are not supported");
                                else
-                                       sig_d = cell->module->MuxGate(NEW_ID, sig_q[0], sig_d[0], sig_e[0]);
-                               ff_neg &= ~NEG_E;
-                               sig_e = SigSpec();
-                               kill_ce = false;
-                               // Now try again as plain DFF.
-                               continue;
-                       } else if (ff_type == FF_ADFF0 || ff_type == FF_ADFF1 || ff_type == FF_ADFFE0 || ff_type == FF_ADFFE1) {
-                               bool has_set = ff_type == FF_ADFF1 || ff_type == FF_ADFFE1;
-                               bool has_en = ff_type == FF_ADFFE0 || ff_type == FF_ADFFE1;
-                               if (kill_ce) {
-                                       ff_type = has_set ? FF_ADFF1 : FF_ADFF0;
-                                       goto unmap_enable;
-                               }
-                               if (!has_en && (supported_cells[has_set ? FF_ADFFE1 : FF_ADFFE0] & initmask)) {
-                                       // Just add enable.
-                                       sig_e = State::S1;
-                                       ff_type = has_set ? FF_ADFFE1 : FF_ADFFE0;
-                                       break;
-                               }
-                               if (supported_cells[has_en ? FF_DFFSRE : FF_DFFSR] & initmask) {
-adff_to_dffsr:
-                                       // Throw in a set/reset, retry in DFFSR/DFFSRE branch.
-                                       if (has_set) {
-                                               sig_s = sig_r;
-                                               sig_r = State::S0;
-                                               if (ff_neg & NEG_R) {
-                                                       ff_neg &= ~NEG_R;
-                                                       ff_neg |= NEG_S;
-                                               }
-                                       } else {
-                                               sig_s = State::S0;
-                                       }
-                                       if (has_en)
-                                               ff_type = FF_DFFSRE;
-                                       else
-                                               ff_type = FF_DFFSR;
-                                       continue;
-                               }
-                               if (has_en && (supported_cells[has_set ? FF_ADFF1 : FF_ADFF0] & initmask)) {
-                                       // Unmap enable.
-                                       ff_type = has_set ? FF_ADFF1 : FF_ADFF0;
-                                       goto unmap_enable;
-                               }
-                               if (supported_dffsr & initmask) {
-                                       goto adff_to_dffsr;
-                               }
-                               log_assert(!((has_set ? supported_adff1 : supported_adff0) & initmask));
-                               // Alright, so this particular combination of initval and
-                               // resetval is not natively supported.  First, try flipping
-                               // them both to see whether this helps.
-                               int flipmask = flip_initmask(initmask);
-                               if ((has_set ? supported_adff0 : supported_adff1) & flipmask) {
-                                       // Checks out, do it.
-                                       ff_type = has_en ? (has_set ? FF_ADFFE0 : FF_ADFFE1) : (has_set ? FF_ADFF0 : FF_ADFF1);
-                                       goto flip_dqi;
-                               }
+                                       fail_ff(ff, "initialized dffs with async set and reset are not supported");
+                       } else {
+                               if (!supported_cells[FF_DLATCHSR])
+                                       fail_ff(ff, "dlatch with async set and reset are not supported");
+                               else
+                                       fail_ff(ff, "initialized dlatch with async set and reset are not supported");
+                       }
+               }
 
-                               if (!supported_adff0 && !supported_adff1) {
-                                       reason = "dffs with async set or reset are not supported";
-                                       goto error;
-                               }
-                               if (!(supported_dff & ~INIT_X)) {
-                                       reason = "initialized dffs are not supported";
-                                       goto error;
-                               }
-                               // If we got here, initialized dff is supported, but not this
-                               // particular reset+init combination (nor its negation).
-                               // The only hope left is breaking down to adff + dff + dlatch + mux.
-                               if (!(supported_dlatch & ~INIT_X)) {
-                                       reason = "unsupported initial value and async reset value combination";
-                                       goto error;
-                               }
+               // If we have to unmap enable anyway, do it before breakdown.
+               if (ff.has_ce && !supported_cells[FF_ADFFE])
+                       ff.unmap_ce();
 
-                               // If we have to unmap enable anyway, do it before breakdown.
-                               if (has_en && !supported_cells[FF_ADFFE0] && !supported_cells[FF_ADFFE1]) {
-                                       ff_type = has_set ? FF_ADFF1 : FF_ADFF0;
-                                       goto unmap_enable;
-                               }
+               log_warning("Emulating async set + reset with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
 
-                               log_warning("Emulating mismatched async reset and init with several FFs and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
-                               initvals.remove_init(sig_q[0]);
-                               Wire *adff_q = cell->module->addWire(NEW_ID);
-                               Wire *dff_q = cell->module->addWire(NEW_ID);
-                               Wire *sel_q = cell->module->addWire(NEW_ID);
-                               initvals.set_init(SigBit(dff_q, 0), initval);
-                               initvals.set_init(SigBit(sel_q, 0), State::S0);
-                               Cell *cell_dff;
-                               Cell *cell_adff;
-                               Cell *cell_sel;
-                               if (!has_en) {
-                                       cell_dff = cell->module->addDffGate(NEW_ID, sig_c, sig_d, dff_q, !(ff_neg & NEG_C));
-                                       cell_adff = cell->module->addAdffGate(NEW_ID, sig_c, sig_r, sig_d, adff_q, has_set, !(ff_neg & NEG_C), !(ff_neg & NEG_R));
-                               } else {
-                                       cell_dff = cell->module->addDffeGate(NEW_ID, sig_c, sig_e, sig_d, dff_q, !(ff_neg & NEG_C), !(ff_neg & NEG_E));
-                                       cell_adff = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_r, sig_d, adff_q, has_set, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_R));
-                               }
-                               cell_sel = cell->module->addDlatchGate(NEW_ID, sig_r, State::S1, sel_q, !(ff_neg & NEG_R));
-                               cell->module->addMuxGate(NEW_ID, dff_q, adff_q, sel_q, sig_q);
-
-                               // Bye, cell.
-                               cell->module->remove(cell);
-                               handle_ff(cell_dff);
-                               handle_ff(cell_adff);
-                               handle_ff(cell_sel);
-                               return;
-                       } else if (ff_type == FF_DFFSR || ff_type == FF_DFFSRE) {
-                               if (kill_ce) {
-                                       ff_type = FF_DFFSR;
-                                       goto unmap_enable;
-                               }
-                               // First, see if mapping/unmapping enable will help.
-                               if (supported_cells[FF_DFFSRE] & initmask) {
-                                       ff_type = FF_DFFSRE;
-                                       sig_e = State::S1;
-                                       break;
-                               }
-                               if (supported_cells[FF_DFFSR] & initmask) {
-                                       ff_type = FF_DFFSR;
-                                       goto unmap_enable;
-                               }
-                               if (supported_dffsr & flip_initmask(initmask)) {
-flip_dqisr:;
-                                       log_warning("Flipping D/Q/init and inserting set/reset fixup to handle init value on %s.%s [%s]\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type));
-                                       SigSpec new_r;
-                                       bool neg_r = (ff_neg & NEG_R);
-                                       bool neg_s = (ff_neg & NEG_S);
-                                       if (!(ff_neg & NEG_S)) {
-                                               if (!(ff_neg & NEG_R))
-                                                       new_r = cell->module->AndnotGate(NEW_ID, sig_s, sig_r);
-                                               else
-                                                       new_r = cell->module->AndGate(NEW_ID, sig_s, sig_r);
-                                       } else {
-                                               if (!(ff_neg & NEG_R))
-                                                       new_r = cell->module->OrGate(NEW_ID, sig_s, sig_r);
-                                               else
-                                                       new_r = cell->module->OrnotGate(NEW_ID, sig_s, sig_r);
-                                       }
-                                       ff_neg &= ~(NEG_R | NEG_S);
-                                       if (neg_r)
-                                               ff_neg |= NEG_S;
-                                       if (neg_s)
-                                               ff_neg |= NEG_R;
-                                       sig_s = sig_r;
-                                       sig_r = new_r;
-                                       goto flip_dqi;
-                               }
-                               // No native DFFSR.  However, if we can conjure
-                               // a SR latch and ADFF, it can still be emulated.
-                               int flipmask = flip_initmask(initmask);
-                               bool init0 = true;
-                               bool init1 = true;
-                               State initsel = State::Sx;
-                               if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && ((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && supported_sr) {
-                                       // OK
-                               } else if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && (supported_sr & INIT_0)) {
-                                       init1 = false;
-                                       initsel = State::S0;
-                               } else if (((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && (supported_sr & INIT_1)) {
-                                       init0 = false;
-                                       initsel = State::S1;
-                               } else if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && (supported_sr & INIT_1)) {
-                                       init1 = false;
-                                       initsel = State::S0;
-                               } else if (((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && (supported_sr & INIT_0)) {
-                                       init0 = false;
-                                       initsel = State::S1;
-                               } else {
-                                       if (!supported_dffsr)
-                                               reason = "dffs with async set and reset are not supported";
-                                       else
-                                               reason = "initialized dffs with async set and reset are not supported";
-                                       goto error;
-                               }
+               log_assert(ff.width == 1);
+               ff.remove();
 
-                               // If we have to unmap enable anyway, do it before breakdown.
-                               if (ff_type == FF_DFFSRE && !supported_cells[FF_ADFFE0] && !supported_cells[FF_ADFFE1]) {
-                                       ff_type = FF_DFFSR;
-                                       goto unmap_enable;
-                               }
+               FfData ff_clr(ff.module, &initvals, NEW_ID);
+               ff_clr.width = ff.width;
+               ff_clr.has_aload = ff.has_aload;
+               ff_clr.sig_aload = ff.sig_aload;
+               ff_clr.pol_aload = ff.pol_aload;
+               ff_clr.sig_ad = ff.sig_ad;
+               ff_clr.has_clk = ff.has_clk;
+               ff_clr.sig_clk = ff.sig_clk;
+               ff_clr.pol_clk = ff.pol_clk;
+               ff_clr.sig_d = ff.sig_d;
+               ff_clr.has_ce = ff.has_ce;
+               ff_clr.sig_ce = ff.sig_ce;
+               ff_clr.pol_ce = ff.pol_ce;
+               ff_clr.has_arst = true;
+               ff_clr.sig_arst = ff.sig_clr;
+               ff_clr.pol_arst = ff.pol_clr;
+               ff_clr.val_arst = Const(State::S0, ff.width);
+               ff_clr.sig_q = ff.module->addWire(NEW_ID, ff.width);
+               ff_clr.val_init = init_clr ? ff.val_init : Const(State::Sx, ff.width);
+               ff_clr.is_fine = ff.is_fine;
 
-                               log_warning("Emulating async set + reset with several FFs and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
-                               initvals.remove_init(sig_q[0]);
-                               Wire *adff0_q = cell->module->addWire(NEW_ID);
-                               Wire *adff1_q = cell->module->addWire(NEW_ID);
-                               Wire *sel_q = cell->module->addWire(NEW_ID);
-                               if (init0)
-                                       initvals.set_init(SigBit(adff0_q, 0), initval);
-                               if (init1)
-                                       initvals.set_init(SigBit(adff1_q, 0), initval);
-                               initvals.set_init(SigBit(sel_q, 0), initsel);
-                               Cell *cell_adff0;
-                               Cell *cell_adff1;
-                               Cell *cell_sel;
-                               if (ff_type == FF_DFFSR) {
-                                       cell_adff0 = cell->module->addAdffGate(NEW_ID, sig_c, sig_r, sig_d, adff0_q, false, !(ff_neg & NEG_C), !(ff_neg & NEG_R));
-                                       cell_adff1 = cell->module->addAdffGate(NEW_ID, sig_c, sig_s, sig_d, adff1_q, true, !(ff_neg & NEG_C), !(ff_neg & NEG_S));
-                               } else {
-                                       cell_adff0 = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_r, sig_d, adff0_q, false, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_R));
-                                       cell_adff1 = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_s, sig_d, adff1_q, true, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_S));
-                               }
-                               cell_sel = cell->module->addSrGate(NEW_ID, sig_s, sig_r, sel_q, !(ff_neg & NEG_S), !(ff_neg & NEG_R));
-                               cell->module->addMuxGate(NEW_ID, adff0_q, adff1_q, sel_q, sig_q);
-
-                               // Bye, cell.
-                               cell->module->remove(cell);
-                               handle_ff(cell_adff0);
-                               handle_ff(cell_adff1);
-                               handle_ff(cell_sel);
+               FfData ff_set(ff.module, &initvals, NEW_ID);
+               ff_set.width = ff.width;
+               ff_set.has_aload = ff.has_aload;
+               ff_set.sig_aload = ff.sig_aload;
+               ff_set.pol_aload = ff.pol_aload;
+               ff_set.sig_ad = ff.sig_ad;
+               ff_set.has_clk = ff.has_clk;
+               ff_set.sig_clk = ff.sig_clk;
+               ff_set.pol_clk = ff.pol_clk;
+               ff_set.sig_d = ff.sig_d;
+               ff_set.has_ce = ff.has_ce;
+               ff_set.sig_ce = ff.sig_ce;
+               ff_set.pol_ce = ff.pol_ce;
+               ff_set.has_arst = true;
+               ff_set.sig_arst = ff.sig_set;
+               ff_set.pol_arst = ff.pol_set;
+               ff_set.val_arst = Const(State::S1, ff.width);
+               ff_set.sig_q = ff.module->addWire(NEW_ID, ff.width);
+               ff_set.val_init = init_set ? ff.val_init : Const(State::Sx, ff.width);
+               ff_set.is_fine = ff.is_fine;
+
+               FfData ff_sel(ff.module, &initvals, NEW_ID);
+               ff_sel.width = ff.width;
+               ff_sel.has_sr = true;
+               ff_sel.pol_clr = ff.pol_clr;
+               ff_sel.pol_set = ff.pol_set;
+               ff_sel.sig_clr = ff.sig_clr;
+               ff_sel.sig_set = ff.sig_set;
+               ff_sel.sig_q = ff.module->addWire(NEW_ID, ff.width);
+               ff_sel.val_init = Const(initsel, ff.width);
+               ff_sel.is_fine = ff.is_fine;
+
+               if (!ff.is_fine)
+                       ff.module->addMux(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q);
+               else
+                       ff.module->addMuxGate(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q);
+
+               legalize_ff(ff_clr);
+               legalize_ff(ff_set);
+               legalize_ff(ff_sel);
+       }
+
+       void legalize_dff(FfData &ff) {
+               if (!try_flip(ff, supported_dff)) {
+                       if (!supported_dff)
+                               fail_ff(ff, "D flip-flops are not supported");
+                       else
+                               fail_ff(ff, "initialized D flip-flops are not supported");
+               }
+
+               int initmask = get_initmask(ff);
+               // Some DFF is supported with this init val.  Just pick a type.
+               if (ff.has_ce && !(supported_dffe & initmask)) {
+                       ff.unmap_ce();
+               }
+
+               if (!ff.has_ce) {
+                       if (supported_cells[FF_DFF] & initmask) {
+                               legalize_finish(ff);
                                return;
-                       } else if (ff_type == FF_SR) {
-                               if (supported_cells[FF_ADLATCH0] & initmask || supported_cells[FF_ADLATCH1] & flip_initmask(initmask)) {
-                                       // Convert to ADLATCH0.  May get converted to ADLATCH1.
-                                       ff_type = FF_ADLATCH0;
-                                       sig_e = sig_s;
-                                       sig_d = State::S1;
-                                       if (ff_neg & NEG_S) {
-                                               ff_neg &= ~NEG_S;
-                                               ff_neg |= NEG_E;
-                                       }
-                                       continue;
-                               } else if (supported_cells[FF_DLATCHSR] & initmask) {
-                                       // Upgrade to DLATCHSR.
-                                       ff_type = FF_DLATCHSR;
-                                       sig_e = State::S0;
-                                       sig_d = State::Sx;
-                                       break;
-                               } else if (supported_dffsr & initmask) {
-                                       // Upgrade to DFFSR.  May get further upgraded to DFFSRE.
-                                       ff_type = FF_DFFSR;
-                                       sig_c = State::S0;
-                                       sig_d = State::Sx;
-                                       continue;
-                               } else if (supported_sr & flip_initmask(initmask)) {
-                                       goto flip_dqisr;
-                               } else {
-                                       if (!supported_sr)
-                                               reason = "sr latches are not supported";
-                                       else
-                                               reason = "initialized sr latches are not supported";
-                                       goto error;
-                               }
-                       } else if (ff_type == FF_DLATCH) {
-                               if (!(supported_dlatch & initmask)) {
-                                       // This init value is not supported at all...
-                                       if (supported_dlatch & flip_initmask(initmask))
-                                               goto flip_dqi;
-
-                                       if ((sig_d == State::S0 && (supported_adff0 & initmask)) ||
-                                                       (sig_d == State::S1 && (supported_adff1 & initmask)) ||
-                                                       (sig_d == State::S0 && (supported_adff1 & flip_initmask(initmask))) ||
-                                                       (sig_d == State::S1 && (supported_adff0 & flip_initmask(initmask)))
-                                       ) {
-                                               // Special case: const-D dlatch can be converted into adff with const clock.
-                                               ff_type = (sig_d == State::S0) ? FF_ADFF0 : FF_ADFF1;
-                                               if (ff_neg & NEG_E) {
-                                                       ff_neg &= ~NEG_E;
-                                                       ff_neg |= NEG_R;
-                                               }
-                                               sig_r = sig_e;
-                                               sig_d = State::Sx;
-                                               sig_c = State::S1;
-                                               continue;
-                                       }
+                       }
+                       // Try adding a set or reset pin.
+                       if (supported_cells[FF_SDFF] & initmask) {
+                               ff.add_dummy_srst();
+                               legalize_finish(ff);
+                               return;
+                       }
+                       if (supported_cells[FF_ADFF] & initmask) {
+                               ff.add_dummy_arst();
+                               legalize_finish(ff);
+                               return;
+                       }
+                       // Try adding async load.
+                       if (supported_cells[FF_ALDFF] & initmask) {
+                               ff.add_dummy_aload();
+                               legalize_finish(ff);
+                               return;
+                       }
+                       // Try adding both.
+                       if (supported_cells[FF_DFFSR] & initmask) {
+                               ff.add_dummy_sr();
+                               legalize_finish(ff);
+                               return;
+                       }
+                       // Nope.  Will need to add enable and go the DFFE route.
+                       ff.add_dummy_ce();
+               }
+               if (supported_cells[FF_DFFE] & initmask) {
+                       legalize_finish(ff);
+                       return;
+               }
+               // Try adding a set or reset pin.
+               if (supported_cells[FF_SDFFCE] & initmask) {
+                       ff.add_dummy_srst();
+                       ff.ce_over_srst = true;
+                       legalize_finish(ff);
+                       return;
+               }
+               if (supported_cells[FF_SDFFE] & initmask) {
+                       ff.add_dummy_srst();
+                       legalize_finish(ff);
+                       return;
+               }
+               if (supported_cells[FF_ADFFE] & initmask) {
+                       ff.add_dummy_arst();
+                       legalize_finish(ff);
+                       return;
+               }
+               if (supported_cells[FF_ALDFFE] & initmask) {
+                       ff.add_dummy_aload();
+                       legalize_finish(ff);
+                       return;
+               }
+               // Try adding both.
+               if (supported_cells[FF_DFFSRE] & initmask) {
+                       ff.add_dummy_sr();
+                       legalize_finish(ff);
+                       return;
+               }
+               log_assert(0);
+       }
 
-                                       if (!supported_dlatch)
-                                               reason = "dlatch are not supported";
-                                       else
-                                               reason = "initialized dlatch are not supported";
-                                       goto error;
-                               }
+       void legalize_sdffce(FfData &ff) {
+               if (!try_flip(ff, supported_cells[FF_SDFFCE] | supported_cells[FF_SDFFE])) {
+                       ff.unmap_srst();
+                       legalize_dff(ff);
+                       return;
+               }
 
-                               // Some DLATCH is supported with this init val.  Just pick a type.
-                               if (supported_cells[FF_ADLATCH0] & initmask) {
-                                       ff_type = FF_ADLATCH0;
-                                       sig_r = State::S0;
-                                       break;
-                               }
-                               if (supported_cells[FF_ADLATCH1] & initmask) {
-                                       ff_type = FF_ADLATCH1;
-                                       sig_r = State::S0;
-                                       break;
-                               }
-                               if (supported_cells[FF_DLATCHSR] & initmask) {
-                                       ff_type = FF_DLATCHSR;
-                                       sig_r = State::S0;
-                                       sig_s = State::S0;
-                                       break;
-                               }
+               int initmask = get_initmask(ff);
+               if (supported_cells[FF_SDFFCE] & initmask) {
+                       // OK
+               } else if (supported_cells[FF_SDFFE] & initmask) {
+                       ff.convert_ce_over_srst(false);
+               } else {
+                       log_assert(0);
+               }
+               legalize_finish(ff);
+       }
+
+       void legalize_sdff(FfData &ff) {
+               if (!try_flip(ff, supported_sdff)) {
+                       ff.unmap_srst();
+                       legalize_dff(ff);
+                       return;
+               }
+
+               int initmask = get_initmask(ff);
+               if (!ff.has_ce) {
+                       if (supported_cells[FF_SDFF] & initmask) {
+                               // OK
+                       } else if (supported_cells[FF_SDFFE] & initmask) {
+                               ff.add_dummy_ce();
+                       } else if (supported_cells[FF_SDFFCE] & initmask) {
+                               ff.add_dummy_ce();
+                               ff.ce_over_srst = true;
+                       } else {
                                log_assert(0);
-                       } else if (ff_type == FF_ADLATCH0 || ff_type == FF_ADLATCH1) {
-                               if (supported_cells[FF_DLATCHSR] & initmask) {
-                                       if (ff_type == FF_ADLATCH1) {
-                                               sig_s = sig_r;
-                                               sig_r = State::S0;
-                                               if (ff_neg & NEG_R) {
-                                                       ff_neg &= ~NEG_R;
-                                                       ff_neg |= NEG_S;
-                                               }
-                                       } else {
-                                               sig_s = State::S0;
-                                       }
-                                       ff_type = FF_DLATCHSR;
-                                       break;
-                               }
-                               FfType flip_type = ff_type == FF_ADLATCH0 ? FF_ADLATCH1 : FF_ADLATCH0;
-                               if ((supported_cells[flip_type] | supported_cells[FF_DLATCHSR]) & flip_initmask(initmask)) {
-                                       ff_type = flip_type;
-                                       goto flip_dqi;
-                               }
+                       }
+               } else {
+                       log_assert(!ff.ce_over_srst);
+                       if (supported_cells[FF_SDFFE] & initmask) {
+                               // OK
+                       } else if (supported_cells[FF_SDFFCE] & initmask) {
+                               ff.convert_ce_over_srst(true);
+                       } else if (supported_cells[FF_SDFF] & initmask) {
+                               ff.unmap_ce();
+                       } else {
+                               log_assert(0);
+                       }
+               }
+               legalize_finish(ff);
+       }
 
-                               if (!supported_cells[FF_ADLATCH0] && !supported_cells[FF_ADLATCH1] && !supported_cells[FF_DLATCHSR]) {
-                                       reason = "dlatch with async set or reset are not supported";
-                                       goto error;
-                               }
-                               if (!(supported_dlatch & ~INIT_X)) {
-                                       reason = "initialized dlatch are not supported";
-                                       goto error;
-                               }
+       void legalize_adff(FfData &ff) {
+               if (!try_flip(ff, supported_adff)) {
+                       if (!supported_adff)
+                               fail_ff(ff, "dffs with async set or reset are not supported");
+                       if (!(supported_dff & (INIT_0 | INIT_1)))
+                               fail_ff(ff, "initialized dffs are not supported");
+
+                       // If we got here, initialized dff is supported, but not this
+                       // particular reset+init combination (nor its negation).
+                       // The only hope left is breaking down to adff + dff + dlatch + mux.
+
+                       if (!((supported_rlatch) & (INIT_0_R1 | INIT_1_R0)))
+                               fail_ff(ff, "unsupported initial value and async reset value combination");
+
+                       // If we have to unmap enable anyway, do it before breakdown.
+                       if (ff.has_ce && !supported_cells[FF_ADFFE])
+                               ff.unmap_ce();
+
+                       if (ff.cell)
+                               log_warning("Emulating mismatched async reset and init with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
+                       emulate_split_init_arst(ff);
+                       return;
+               }
 
-                               // If we got here, initialized dlatch is supported, but not this
-                               // particular reset+init combination (nor its negation).
-                               // The only hope left is breaking down to adff + dff + dlatch + mux.
-
-                               log_warning("Emulating mismatched async reset and init with several latches and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
-                               initvals.remove_init(sig_q[0]);
-                               Wire *adlatch_q = cell->module->addWire(NEW_ID);
-                               Wire *dlatch_q = cell->module->addWire(NEW_ID);
-                               Wire *sel_q = cell->module->addWire(NEW_ID);
-                               initvals.set_init(SigBit(dlatch_q, 0), initval);
-                               initvals.set_init(SigBit(sel_q, 0), State::S0);
-                               Cell *cell_dlatch;
-                               Cell *cell_adlatch;
-                               Cell *cell_sel;
-                               cell_dlatch = cell->module->addDlatchGate(NEW_ID, sig_e, sig_d, dlatch_q, !(ff_neg & NEG_E));
-                               cell_adlatch = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_r, sig_d, adlatch_q, ff_type == FF_ADLATCH1, !(ff_neg & NEG_E), !(ff_neg & NEG_R));
-                               cell_sel = cell->module->addDlatchGate(NEW_ID, sig_r, State::S1, sel_q, !(ff_neg & NEG_R));
-                               cell->module->addMuxGate(NEW_ID, dlatch_q, adlatch_q, sel_q, sig_q);
-
-                               // Bye, cell.
-                               cell->module->remove(cell);
-                               handle_ff(cell_dlatch);
-                               handle_ff(cell_adlatch);
-                               handle_ff(cell_sel);
+               int initmask = get_initmask(ff);
+               if (ff.has_ce && !(supported_adffe & initmask)) {
+                       ff.unmap_ce();
+               }
+
+               if (!ff.has_ce) {
+                       if (supported_cells[FF_ADFF] & initmask) {
+                               legalize_finish(ff);
                                return;
-                       } else if (ff_type == FF_DLATCHSR) {
-                               if (supported_cells[FF_DLATCHSR] & flip_initmask(initmask)) {
-                                       goto flip_dqisr;
-                               }
-                               // No native DFFSR.  However, if we can conjure
-                               // a SR latch and ADFF, it can still be emulated.
-                               int flipmask = flip_initmask(initmask);
-                               bool init0 = true;
-                               bool init1 = true;
-                               State initsel = State::Sx;
-                               if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && ((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && supported_sr) {
-                                       // OK
-                               } else if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && (supported_sr & INIT_0)) {
-                                       init1 = false;
-                                       initsel = State::S0;
-                               } else if (((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && (supported_sr & INIT_1)) {
-                                       init0 = false;
-                                       initsel = State::S1;
-                               } else if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && (supported_sr & INIT_1)) {
-                                       init1 = false;
-                                       initsel = State::S0;
-                               } else if (((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && (supported_sr & INIT_0)) {
-                                       init0 = false;
-                                       initsel = State::S1;
-                               } else {
-                                       if (!supported_cells[FF_DLATCHSR])
-                                               reason = "dlatch with async set and reset are not supported";
-                                       else
-                                               reason = "initialized dlatch with async set and reset are not supported";
-                                       goto error;
-                               }
+                       }
+                       // Try converting to async load.
+                       if (supported_cells[FF_ALDFF] & initmask) {
+                               ff.arst_to_aload();
+                               legalize_finish(ff);
+                               return;
+                       }
+                       // Try convertint to SR.
+                       if (supported_cells[FF_DFFSR] & initmask) {
+                               ff.arst_to_sr();
+                               legalize_finish(ff);
+                               return;
+                       }
+                       ff.add_dummy_ce();
+               }
+               if (supported_cells[FF_ADFFE] & initmask) {
+                       legalize_finish(ff);
+                       return;
+               }
+               // Try converting to async load.
+               if (supported_cells[FF_ALDFFE] & initmask) {
+                       ff.arst_to_aload();
+                       legalize_finish(ff);
+                       return;
+               }
+               // Try convertint to SR.
+               if (supported_cells[FF_DFFSRE] & initmask) {
+                       ff.arst_to_sr();
+                       legalize_finish(ff);
+                       return;
+               }
+               log_assert(0);
+       }
+
+       void legalize_aldff(FfData &ff) {
+               if (!try_flip(ff, supported_aldff)) {
+                       ff.aload_to_sr();
+                       emulate_split_set_clr(ff);
+                       return;
+               }
+
+               int initmask = get_initmask(ff);
+               if (ff.has_ce && !(supported_aldffe & initmask)) {
+                       ff.unmap_ce();
+               }
 
-                               log_warning("Emulating async set + reset with several latches and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
-                               initvals.remove_init(sig_q[0]);
-                               Wire *adlatch0_q = cell->module->addWire(NEW_ID);
-                               Wire *adlatch1_q = cell->module->addWire(NEW_ID);
-                               Wire *sel_q = cell->module->addWire(NEW_ID);
-                               if (init0)
-                                       initvals.set_init(SigBit(adlatch0_q, 0), initval);
-                               if (init1)
-                                       initvals.set_init(SigBit(adlatch1_q, 0), initval);
-                               initvals.set_init(SigBit(sel_q, 0), initsel);
-                               Cell *cell_adlatch0;
-                               Cell *cell_adlatch1;
-                               Cell *cell_sel;
-                               cell_adlatch0 = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_r, sig_d, adlatch0_q, false, !(ff_neg & NEG_E), !(ff_neg & NEG_R));
-                               cell_adlatch1 = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_s, sig_d, adlatch1_q, true, !(ff_neg & NEG_E), !(ff_neg & NEG_S));
-                               cell_sel = cell->module->addSrGate(NEW_ID, sig_s, sig_r, sel_q, !(ff_neg & NEG_S), !(ff_neg & NEG_R));
-                               cell->module->addMuxGate(NEW_ID, adlatch0_q, adlatch1_q, sel_q, sig_q);
-
-                               // Bye, cell.
-                               cell->module->remove(cell);
-                               handle_ff(cell_adlatch0);
-                               handle_ff(cell_adlatch1);
-                               handle_ff(cell_sel);
+               if (!ff.has_ce) {
+                       if (supported_cells[FF_ALDFF] & initmask) {
+                               legalize_finish(ff);
                                return;
-                       } else if (ff_type == FF_SDFF0 || ff_type == FF_SDFF1 || ff_type == FF_SDFFE0 || ff_type == FF_SDFFE1 || ff_type == FF_SDFFCE0 || ff_type == FF_SDFFCE1) {
-                               bool has_set = ff_type == FF_SDFF1 || ff_type == FF_SDFFE1 || ff_type == FF_SDFFCE1;
-                               bool has_en = ff_type == FF_SDFFE0 || ff_type == FF_SDFFE1;
-                               bool has_ce = ff_type == FF_SDFFCE0 || ff_type == FF_SDFFCE1;
-
-                               if (has_en) {
-                                       if (kill_ce || kill_srst) {
-                                               ff_type = has_set ? FF_SDFF1 : FF_SDFF0;
-                                               goto unmap_enable;
-                                       }
-                               } else if (has_ce) {
-                                       if (kill_ce || kill_srst)
-                                               goto unmap_srst;
-                               } else {
-                                       log_assert(!kill_ce);
-                                       if (kill_srst)
-                                               goto unmap_srst;
-                               }
+                       }
+                       if (supported_cells[FF_DFFSR] & initmask) {
+                               ff.aload_to_sr();
+                               legalize_finish(ff);
+                               return;
+                       }
+                       ff.add_dummy_ce();
+               }
+               if (supported_cells[FF_ALDFFE] & initmask) {
+                       legalize_finish(ff);
+                       return;
+               }
+               if (supported_cells[FF_DFFSRE] & initmask) {
+                       ff.aload_to_sr();
+                       legalize_finish(ff);
+                       return;
+               }
+               log_assert(0);
+       }
 
-                               if (!has_ce) {
-                                       if (!has_en && (supported_cells[has_set ? FF_SDFFE1 : FF_SDFFE0] & initmask)) {
-                                               // Just add enable.
-                                               sig_e = State::S1;
-                                               ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0;
-                                               break;
-                                       }
-                                       if (!has_en && (supported_cells[has_set ? FF_SDFFCE1 : FF_SDFFCE0] & initmask)) {
-                                               // Just add enable.
-                                               sig_e = State::S1;
-                                               ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0;
-                                               break;
-                                       }
-                                       if (has_en && (supported_cells[has_set ? FF_SDFFCE1 : FF_SDFFCE0] & initmask)) {
-                                               // Convert sdffe to sdffce
-                                               if (!(ff_neg & NEG_E)) {
-                                                       if (!(ff_neg & NEG_R))
-                                                               sig_e = cell->module->OrGate(NEW_ID, sig_e, sig_r);
-                                                       else
-                                                               sig_e = cell->module->OrnotGate(NEW_ID, sig_e, sig_r);
-                                               } else {
-                                                       if (!(ff_neg & NEG_R))
-                                                               sig_e = cell->module->AndnotGate(NEW_ID, sig_e, sig_r);
-                                                       else
-                                                               sig_e = cell->module->AndGate(NEW_ID, sig_e, sig_r);
-                                               }
-                                               ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0;
-                                               break;
-                                       }
-                                       if (has_en && (supported_cells[has_set ? FF_SDFF1 : FF_SDFF0] & initmask)) {
-                                               // Unmap enable.
-                                               ff_type = has_set ? FF_SDFF1 : FF_SDFF0;
-                                               goto unmap_enable;
-                                       }
-                                       log_assert(!((has_set ? supported_sdff1 : supported_sdff0) & initmask));
-                               } else {
-                                       if ((has_set ? supported_sdff1 : supported_sdff0) & initmask) {
-                                               // Convert sdffce to sdffe, which may be further converted to sdff.
-                                               if (!(ff_neg & NEG_R)) {
-                                                       if (!(ff_neg & NEG_E))
-                                                               sig_r = cell->module->AndGate(NEW_ID, sig_r, sig_e);
-                                                       else
-                                                               sig_r = cell->module->AndnotGate(NEW_ID, sig_r, sig_e);
-                                               } else {
-                                                       if (!(ff_neg & NEG_E))
-                                                               sig_r = cell->module->OrnotGate(NEW_ID, sig_r, sig_e);
-                                                       else
-                                                               sig_r = cell->module->OrGate(NEW_ID, sig_r, sig_e);
-                                               }
-                                               ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0;
-                                               continue;
-                                       }
+       void legalize_dffsr(FfData &ff) {
+               if (!try_flip(ff, supported_dffsr)) {
+                       emulate_split_set_clr(ff);
+                       return;
+               }
+
+               int initmask = get_initmask(ff);
+               if (ff.has_ce && !(supported_cells[FF_DFFSRE] & initmask)) {
+                       ff.unmap_ce();
+               }
+
+               if (!ff.has_ce) {
+                       if (supported_cells[FF_DFFSR] & initmask) {
+                               legalize_finish(ff);
+                               return;
+                       }
+                       ff.add_dummy_ce();
+               }
+
+               log_assert(supported_cells[FF_DFFSRE] & initmask);
+               legalize_finish(ff);
+       }
+
+       void legalize_dlatch(FfData &ff) {
+               if (!try_flip(ff, supported_dlatch)) {
+                       if (!supported_dlatch)
+                               fail_ff(ff, "D latches are not supported");
+                       else
+                               fail_ff(ff, "initialized D latches are not supported");
+               }
+
+               int initmask = get_initmask(ff);
+               // Some DLATCH is supported with this init val.  Just pick a type.
+               if (supported_cells[FF_DLATCH] & initmask) {
+                       legalize_finish(ff);
+               } else if (supported_cells[FF_ADLATCH] & initmask) {
+                       ff.add_dummy_arst();
+                       legalize_finish(ff);
+               } else if (supported_cells[FF_DLATCHSR] & initmask) {
+                       ff.add_dummy_sr();
+                       legalize_finish(ff);
+               } else if (supported_cells[FF_ALDFF] & initmask) {
+                       ff.add_dummy_clk();
+                       legalize_finish(ff);
+               } else if (supported_cells[FF_ALDFFE] & initmask) {
+                       ff.add_dummy_clk();
+                       ff.add_dummy_ce();
+                       legalize_finish(ff);
+               } else if (supported_sr & initmask) {
+                       ff.aload_to_sr();
+                       legalize_sr(ff);
+               } else {
+                       log_assert(0);
+               }
+       }
+
+       void legalize_adlatch(FfData &ff) {
+               if (!try_flip(ff, supported_adlatch)) {
+                       if (!supported_adlatch)
+                               fail_ff(ff, "D latches with async set or reset are not supported");
+                       if (!(supported_dlatch & (INIT_0 | INIT_1)))
+                               fail_ff(ff, "initialized D latches are not supported");
+
+                       // If we got here, initialized dlatch is supported, but not this
+                       // particular reset+init combination (nor its negation).
+                       // The only hope left is breaking down to adlatch + dlatch + dlatch + mux.
+
+                       if (ff.cell)
+                               log_warning("Emulating mismatched async reset and init with several latches and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
+                       ff.remove();
+
+                       emulate_split_init_arst(ff);
+                       return;
+               }
+               int initmask = get_initmask(ff);
+               if (supported_cells[FF_ADLATCH] & initmask) {
+                       // OK
+               } else if (supported_cells[FF_DLATCHSR] & initmask) {
+                       ff.arst_to_sr();
+               } else {
+                       log_assert(0);
+               }
+               legalize_finish(ff);
+       }
+
+       void legalize_dlatchsr(FfData &ff) {
+               if (!try_flip(ff, supported_cells[FF_DLATCHSR])) {
+                       emulate_split_set_clr(ff);
+                       return;
+               }
+               legalize_finish(ff);
+       }
+
+       void legalize_rlatch(FfData &ff) {
+               if (!try_flip(ff, supported_rlatch)) {
+                       if (!supported_dlatch)
+                               fail_ff(ff, "D latches are not supported");
+                       else
+                               fail_ff(ff, "initialized D latches are not supported");
+               }
+
+               int initmask = get_initmask(ff);
+               if (((supported_dlatch_plain & 7) * 0x111) & initmask) {
+                       ff.arst_to_aload();
+                       legalize_dlatch(ff);
+               } else if (supported_sr & initmask) {
+                       ff.arst_to_sr();
+                       legalize_sr(ff);
+               } else if (supported_adff & initmask) {
+                       ff.add_dummy_clk();
+                       legalize_adff(ff);
+               } else {
+                       log_assert(0);
+               }
+       }
+
+       void legalize_sr(FfData &ff) {
+               if (!try_flip(ff, supported_sr)) {
+                       if (!supported_sr)
+                               fail_ff(ff, "sr latches are not supported");
+                       else
+                               fail_ff(ff, "initialized sr latches are not supported");
+               }
+               int initmask = get_initmask(ff);
+               if (supported_cells[FF_SR] & initmask) {
+                       // OK
+               } else if (supported_cells[FF_DLATCHSR] & initmask) {
+                       // Upgrade to DLATCHSR.
+                       ff.add_dummy_aload();
+               } else if (supported_cells[FF_DFFSR] & initmask) {
+                       // Upgrade to DFFSR.
+                       ff.add_dummy_clk();
+               } else if (supported_cells[FF_DFFSRE] & initmask) {
+                       // Upgrade to DFFSRE.
+                       ff.add_dummy_clk();
+                       ff.add_dummy_ce();
+               } else if (supported_cells[FF_ADLATCH] & (initmask << 4)) {
+                       ff.has_sr = false;
+                       ff.has_aload = true;
+                       ff.has_arst = true;
+                       ff.pol_arst = ff.pol_clr;
+                       ff.sig_arst = ff.sig_clr;
+                       ff.sig_aload = ff.sig_set;
+                       ff.pol_aload = ff.pol_set;
+                       ff.sig_ad = State::S1;
+                       ff.val_arst = State::S0;
+               } else if (supported_cells[FF_ADLATCH] & (flip_initmask(initmask) << 8)) {
+                       ff.has_sr = false;
+                       ff.has_aload = true;
+                       ff.has_arst = true;
+                       ff.pol_arst = ff.pol_clr;
+                       ff.sig_arst = ff.sig_clr;
+                       ff.sig_aload = ff.sig_set;
+                       ff.pol_aload = ff.pol_set;
+                       ff.sig_ad = State::S0;
+                       ff.val_arst = State::S1;
+                       ff.remove_init();
+                       Wire *new_q = ff.module->addWire(NEW_ID);
+                       if (ff.is_fine)
+                               ff.module->addNotGate(NEW_ID, new_q, ff.sig_q);
+                       else
+                               ff.module->addNot(NEW_ID, new_q, ff.sig_q);
+                       ff.sig_q = new_q;
+                       if (ff.val_init == State::S0)
+                               ff.val_init = State::S1;
+                       else if (ff.val_init == State::S1)
+                               ff.val_init = State::S0;
+               } else {
+                       log_assert(0);
+               }
+               legalize_finish(ff);
+       }
+
+       void fixup_reset_x(FfData &ff, int supported) {
+               for (int i = 0; i < ff.width; i++) {
+                       int mask;
+                       if (ff.val_init[i] == State::S0)
+                               mask = INIT_0;
+                       else if (ff.val_init[i] == State::S1)
+                               mask = INIT_1;
+                       else
+                               mask = INIT_X;
+                       if (ff.has_arst) {
+                               if (ff.val_arst[i] == State::Sx) {
+                                       if (!(supported & (mask << 8)))
+                                               ff.val_arst[i] = State::S0;
+                                       if (!(supported & (mask << 4)))
+                                               ff.val_arst[i] = State::S1;
                                }
-                               // Alright, so this particular combination of initval and
-                               // resetval is not natively supported.  First, try flipping
-                               // them both to see whether this helps.
-                               if ((has_set ? supported_sdff0 : supported_sdff1) & flip_initmask(initmask)) {
-                                       // Checks out, do it.
-                                       ff_type = has_ce ? (has_set ? FF_SDFFCE0 : FF_SDFFCE1) : has_en ? (has_set ? FF_SDFFE0 : FF_SDFFE1) : (has_set ? FF_SDFF0 : FF_SDFF1);
-                                       goto flip_dqi;
+                       }
+                       if (ff.has_srst) {
+                               if (ff.val_srst[i] == State::Sx) {
+                                       if (!(supported & (mask << 8)))
+                                               ff.val_srst[i] = State::S0;
+                                       if (!(supported & (mask << 4)))
+                                               ff.val_srst[i] = State::S1;
                                }
+                       }
+               }
+       }
 
-                               // Nope.  No way to get SDFF* of the right kind, so unmap it.
-                               // For SDFFE, the enable has to be unmapped first.
-                               if (has_en) {
-                                       ff_type = has_set ? FF_SDFF1 : FF_SDFF0;
-                                       goto unmap_enable;
-                               }
-unmap_srst:
-                               if (has_ce)
-                                       ff_type = FF_DFFE;
-                               else
-                                       ff_type = FF_DFF;
-                               if (ff_neg & NEG_R)
-                                       sig_d = cell->module->MuxGate(NEW_ID, has_set ? State::S1 : State::S0, sig_d[0], sig_r[0]);
+       void legalize_ff(FfData &ff) {
+               if (ff.has_gclk)
+                       return;
+
+               // TODO: consider supporting coarse as well.
+               if (!ff.is_fine)
+                       return;
+
+               if (mince && ff.has_ce && ff.sig_ce[0].wire && ce_used[ff.sig_ce[0]] < mince)
+                       ff.unmap_ce();
+               if (minsrst && ff.has_srst && ff.sig_srst[0].wire && srst_used[ff.sig_srst[0]] < minsrst)
+                       ff.unmap_srst();
+
+               if (ff.has_clk) {
+                       if (ff.has_sr) {
+                               legalize_dffsr(ff);
+                       } else if (ff.has_aload) {
+                               legalize_aldff(ff);
+                       } else if (ff.has_arst) {
+                               legalize_adff(ff);
+                       } else if (ff.has_srst) {
+                               if (ff.has_ce && ff.ce_over_srst)
+                                       legalize_sdffce(ff);
                                else
-                                       sig_d = cell->module->MuxGate(NEW_ID, sig_d[0], has_set ? State::S1 : State::S0, sig_r[0]);
-                               ff_neg &= ~NEG_R;
-                               sig_r = SigSpec();
-                               kill_srst = false;
-                               continue;
+                                       legalize_sdff(ff);
+                       } else {
+                               legalize_dff(ff);
+                       }
+               } else if (ff.has_aload) {
+                       if (ff.has_sr) {
+                               legalize_dlatchsr(ff);
+                       } else if (ff.has_arst) {
+                               legalize_adlatch(ff);
+                       } else {
+                               legalize_dlatch(ff);
+                       }
+               } else {
+                       if (ff.has_sr) {
+                               legalize_sr(ff);
+                       } else if (ff.has_arst) {
+                               legalize_rlatch(ff);
                        } else {
                                log_assert(0);
                        }
                }
-cell_ok:
+       }
+
+       void flip_pol(FfData &ff, SigSpec &sig, bool &pol) {
+               if (sig == State::S0) {
+                       sig = State::S1;
+               } else if (sig == State::S1) {
+                       sig = State::S0;
+               } else if (ff.is_fine) {
+                       sig = ff.module->NotGate(NEW_ID, sig);
+               } else {
+                       sig = ff.module->Not(NEW_ID, sig);
+               }
+               pol = !pol;
+       }
 
+       void legalize_finish(FfData &ff) {
+               int ff_type = get_ff_type(ff);
+               int initmask = get_initmask(ff);
+               log_assert(supported_cells[ff_type] & initmask);
+               int ff_neg = 0;
+               if (ff.has_sr) {
+                       if (!ff.pol_clr)
+                               ff_neg |= NEG_R;
+                       if (!ff.pol_set)
+                               ff_neg |= NEG_S;
+               }
+               if (ff.has_arst) {
+                       if (!ff.pol_arst)
+                               ff_neg |= NEG_R;
+               }
+               if (ff.has_srst) {
+                       if (!ff.pol_srst)
+                               ff_neg |= NEG_R;
+               }
+               if (ff.has_aload) {
+                       if (!ff.pol_aload)
+                               ff_neg |= NEG_L;
+               }
+               if (ff.has_clk) {
+                       if (!ff.pol_clk)
+                               ff_neg |= NEG_C;
+               }
+               if (ff.has_ce) {
+                       if (!ff.pol_ce)
+                               ff_neg |= NEG_CE;
+               }
                if (!(supported_cells_neg[ff_type][ff_neg] & initmask)) {
                        // Cell is supported, but not with those polarities.
                        // Will need to add some inverters.
@@ -917,182 +998,27 @@ cell_ok:
                                if (supported_cells_neg[ff_type][ff_neg ^ xneg] & initmask)
                                        break;
                        log_assert(xneg < NUM_NEG);
-                       if (xneg & NEG_R)
-                               sig_r = cell->module->NotGate(NEW_ID, sig_r[0]);
-                       if (xneg & NEG_S)
-                               sig_s = cell->module->NotGate(NEW_ID, sig_s[0]);
-                       if (xneg & NEG_E)
-                               sig_e = cell->module->NotGate(NEW_ID, sig_e[0]);
+                       if (xneg & NEG_CE)
+                               flip_pol(ff, ff.sig_ce, ff.pol_ce);
+                       if (ff.has_sr) {
+                               if (xneg & NEG_R)
+                                       flip_pol(ff, ff.sig_clr, ff.pol_clr);
+                               if (xneg & NEG_S)
+                                       flip_pol(ff, ff.sig_set, ff.pol_set);
+                       }
+                       if (ff.has_arst && xneg & NEG_R)
+                               flip_pol(ff, ff.sig_arst, ff.pol_arst);
+                       if (ff.has_srst && xneg & NEG_R)
+                               flip_pol(ff, ff.sig_srst, ff.pol_srst);
+                       if (xneg & NEG_L)
+                               flip_pol(ff, ff.sig_aload, ff.pol_aload);
                        if (xneg & NEG_C)
-                               sig_c = cell->module->NotGate(NEW_ID, sig_c[0]);
+                               flip_pol(ff, ff.sig_clk, ff.pol_clk);
                        ff_neg ^= xneg;
                }
 
-               cell->unsetPort(ID::D);
-               cell->unsetPort(ID::Q);
-               cell->unsetPort(ID::C);
-               cell->unsetPort(ID::E);
-               cell->unsetPort(ID::S);
-               cell->unsetPort(ID::R);
-               switch (ff_type) {
-                       case FF_DFF:
-                               cell->type = IdString(stringf("$_DFF_%c_",
-                                               (ff_neg & NEG_C) ? 'N' : 'P'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::C, sig_c);
-                               break;
-                       case FF_DFFE:
-                               cell->type = IdString(stringf("$_DFFE_%c%c_",
-                                               (ff_neg & NEG_C) ? 'N' : 'P',
-                                               (ff_neg & NEG_E) ? 'N' : 'P'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::C, sig_c);
-                               cell->setPort(ID::E, sig_e);
-                               break;
-                       case FF_ADFF0:
-                       case FF_ADFF1:
-                               cell->type = IdString(stringf("$_DFF_%c%c%c_",
-                                               (ff_neg & NEG_C) ? 'N' : 'P',
-                                               (ff_neg & NEG_R) ? 'N' : 'P',
-                                               (ff_type == FF_ADFF1) ? '1' : '0'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::C, sig_c);
-                               cell->setPort(ID::R, sig_r);
-                               break;
-                       case FF_ADFFE0:
-                       case FF_ADFFE1:
-                               cell->type = IdString(stringf("$_DFFE_%c%c%c%c_",
-                                               (ff_neg & NEG_C) ? 'N' : 'P',
-                                               (ff_neg & NEG_R) ? 'N' : 'P',
-                                               (ff_type == FF_ADFFE1) ? '1' : '0',
-                                               (ff_neg & NEG_E) ? 'N' : 'P'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::C, sig_c);
-                               cell->setPort(ID::E, sig_e);
-                               cell->setPort(ID::R, sig_r);
-                               break;
-                       case FF_DFFSR:
-                               cell->type = IdString(stringf("$_DFFSR_%c%c%c_",
-                                               (ff_neg & NEG_C) ? 'N' : 'P',
-                                               (ff_neg & NEG_S) ? 'N' : 'P',
-                                               (ff_neg & NEG_R) ? 'N' : 'P'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::C, sig_c);
-                               cell->setPort(ID::S, sig_s);
-                               cell->setPort(ID::R, sig_r);
-                               break;
-                       case FF_DFFSRE:
-                               cell->type = IdString(stringf("$_DFFSRE_%c%c%c%c_",
-                                               (ff_neg & NEG_C) ? 'N' : 'P',
-                                               (ff_neg & NEG_S) ? 'N' : 'P',
-                                               (ff_neg & NEG_R) ? 'N' : 'P',
-                                               (ff_neg & NEG_E) ? 'N' : 'P'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::C, sig_c);
-                               cell->setPort(ID::E, sig_e);
-                               cell->setPort(ID::S, sig_s);
-                               cell->setPort(ID::R, sig_r);
-                               break;
-                       case FF_SDFF0:
-                       case FF_SDFF1:
-                               cell->type = IdString(stringf("$_SDFF_%c%c%c_",
-                                               (ff_neg & NEG_C) ? 'N' : 'P',
-                                               (ff_neg & NEG_R) ? 'N' : 'P',
-                                               (ff_type == FF_SDFF1) ? '1' : '0'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::C, sig_c);
-                               cell->setPort(ID::R, sig_r);
-                               break;
-                       case FF_SDFFE0:
-                       case FF_SDFFE1:
-                               cell->type = IdString(stringf("$_SDFFE_%c%c%c%c_",
-                                               (ff_neg & NEG_C) ? 'N' : 'P',
-                                               (ff_neg & NEG_R) ? 'N' : 'P',
-                                               (ff_type == FF_SDFFE1) ? '1' : '0',
-                                               (ff_neg & NEG_E) ? 'N' : 'P'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::C, sig_c);
-                               cell->setPort(ID::E, sig_e);
-                               cell->setPort(ID::R, sig_r);
-                               break;
-                       case FF_SDFFCE0:
-                       case FF_SDFFCE1:
-                               cell->type = IdString(stringf("$_SDFFCE_%c%c%c%c_",
-                                               (ff_neg & NEG_C) ? 'N' : 'P',
-                                               (ff_neg & NEG_R) ? 'N' : 'P',
-                                               (ff_type == FF_SDFFCE1) ? '1' : '0',
-                                               (ff_neg & NEG_E) ? 'N' : 'P'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::C, sig_c);
-                               cell->setPort(ID::E, sig_e);
-                               cell->setPort(ID::R, sig_r);
-                               break;
-                       case FF_DLATCH:
-                               cell->type = IdString(stringf("$_DLATCH_%c_",
-                                               (ff_neg & NEG_E) ? 'N' : 'P'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::E, sig_e);
-                               break;
-                       case FF_ADLATCH0:
-                       case FF_ADLATCH1:
-                               cell->type = IdString(stringf("$_DLATCH_%c%c%c_",
-                                               (ff_neg & NEG_E) ? 'N' : 'P',
-                                               (ff_neg & NEG_R) ? 'N' : 'P',
-                                               (ff_type == FF_ADLATCH1) ? '1' : '0'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::E, sig_e);
-                               cell->setPort(ID::R, sig_r);
-                               break;
-                       case FF_DLATCHSR:
-                               cell->type = IdString(stringf("$_DLATCHSR_%c%c%c_",
-                                               (ff_neg & NEG_E) ? 'N' : 'P',
-                                               (ff_neg & NEG_S) ? 'N' : 'P',
-                                               (ff_neg & NEG_R) ? 'N' : 'P'
-                                       ));
-                               cell->setPort(ID::D, sig_d);
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::E, sig_e);
-                               cell->setPort(ID::S, sig_s);
-                               cell->setPort(ID::R, sig_r);
-                               break;
-                       case FF_SR:
-                               cell->type = IdString(stringf("$_SR_%c%c_",
-                                               (ff_neg & NEG_S) ? 'N' : 'P',
-                                               (ff_neg & NEG_R) ? 'N' : 'P'
-                                       ));
-                               cell->setPort(ID::Q, sig_q);
-                               cell->setPort(ID::S, sig_s);
-                               cell->setPort(ID::R, sig_r);
-                               break;
-                       default:
-                               log_assert(0);
-               }
-               return;
-
-error:
-               log_error("FF %s.%s (type %s) cannot be legalized: %s\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type), reason);
+               fixup_reset_x(ff, supported_cells_neg[ff_type][ff_neg]);
+               ff.emit();
        }
 
        void execute(std::vector<std::string> args, RTLIL::Design *design) override
@@ -1114,79 +1040,83 @@ error:
                        if (args[argidx] == "-cell" && argidx + 2 < args.size()) {
                                std::string celltype = args[++argidx];
                                std::string inittype = args[++argidx];
-                               enum FfType ff_type[2] = {NUM_FFTYPES, NUM_FFTYPES};
+                               enum FfType ff_type;
                                char pol_c = 0;
-                               char pol_e = 0;
+                               char pol_l = 0;
                                char pol_s = 0;
                                char pol_r = 0;
+                               char pol_ce = 0;
                                char srval = 0;
                                if (celltype.substr(0, 5) == "$_SR_" && celltype.size() == 8 && celltype[7] == '_') {
-                                       ff_type[0] = FF_SR;
+                                       ff_type = FF_SR;
                                        pol_s = celltype[5];
                                        pol_r = celltype[6];
                                } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 8 && celltype[7] == '_') {
-                                       ff_type[0] = FF_DFF;
+                                       ff_type = FF_DFF;
                                        pol_c = celltype[6];
                                } else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 10 && celltype[9] == '_') {
-                                       ff_type[0] = FF_DFFE;
+                                       ff_type = FF_DFFE;
                                        pol_c = celltype[7];
-                                       pol_e = celltype[8];
+                                       pol_ce = celltype[8];
                                } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 10 && celltype[9] == '_') {
-                                       ff_type[0] = FF_ADFF0;
-                                       ff_type[1] = FF_ADFF1;
+                                       ff_type = FF_ADFF;
                                        pol_c = celltype[6];
                                        pol_r = celltype[7];
                                        srval = celltype[8];
                                } else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 12 && celltype[11] == '_') {
-                                       ff_type[0] = FF_ADFFE0;
-                                       ff_type[1] = FF_ADFFE1;
+                                       ff_type = FF_ADFFE;
                                        pol_c = celltype[7];
                                        pol_r = celltype[8];
                                        srval = celltype[9];
-                                       pol_e = celltype[10];
+                                       pol_ce = celltype[10];
+                               } else if (celltype.substr(0, 8) == "$_ALDFF_" && celltype.size() == 11 && celltype[10] == '_') {
+                                       ff_type = FF_ALDFF;
+                                       pol_c = celltype[8];
+                                       pol_l = celltype[9];
+                               } else if (celltype.substr(0, 9) == "$_ALDFFE_" && celltype.size() == 13 && celltype[12] == '_') {
+                                       ff_type = FF_ALDFFE;
+                                       pol_c = celltype[9];
+                                       pol_l = celltype[10];
+                                       pol_ce = celltype[11];
                                } else if (celltype.substr(0, 8) == "$_DFFSR_" && celltype.size() == 12 && celltype[11] == '_') {
-                                       ff_type[0] = FF_DFFSR;
+                                       ff_type = FF_DFFSR;
                                        pol_c = celltype[8];
                                        pol_s = celltype[9];
                                        pol_r = celltype[10];
                                } else if (celltype.substr(0, 9) == "$_DFFSRE_" && celltype.size() == 14 && celltype[13] == '_') {
-                                       ff_type[0] = FF_DFFSRE;
+                                       ff_type = FF_DFFSRE;
                                        pol_c = celltype[9];
                                        pol_s = celltype[10];
                                        pol_r = celltype[11];
-                                       pol_e = celltype[12];
+                                       pol_ce = celltype[12];
                                } else if (celltype.substr(0, 7) == "$_SDFF_" && celltype.size() == 11 && celltype[10] == '_') {
-                                       ff_type[0] = FF_SDFF0;
-                                       ff_type[1] = FF_SDFF1;
+                                       ff_type = FF_SDFF;
                                        pol_c = celltype[7];
                                        pol_r = celltype[8];
                                        srval = celltype[9];
                                } else if (celltype.substr(0, 8) == "$_SDFFE_" && celltype.size() == 13 && celltype[12] == '_') {
-                                       ff_type[0] = FF_SDFFE0;
-                                       ff_type[1] = FF_SDFFE1;
+                                       ff_type = FF_SDFFE;
                                        pol_c = celltype[8];
                                        pol_r = celltype[9];
                                        srval = celltype[10];
-                                       pol_e = celltype[11];
+                                       pol_ce = celltype[11];
                                } else if (celltype.substr(0, 9) == "$_SDFFCE_" && celltype.size() == 14 && celltype[13] == '_') {
-                                       ff_type[0] = FF_SDFFCE0;
-                                       ff_type[1] = FF_SDFFCE1;
+                                       ff_type = FF_SDFFCE;
                                        pol_c = celltype[9];
                                        pol_r = celltype[10];
                                        srval = celltype[11];
-                                       pol_e = celltype[12];
+                                       pol_ce = celltype[12];
                                } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 11 && celltype[10] == '_') {
-                                       ff_type[0] = FF_DLATCH;
-                                       pol_e = celltype[9];
+                                       ff_type = FF_DLATCH;
+                                       pol_l = celltype[9];
                                } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 13 && celltype[12] == '_') {
-                                       ff_type[0] = FF_ADLATCH0;
-                                       ff_type[1] = FF_ADLATCH1;
-                                       pol_e = celltype[9];
+                                       ff_type = FF_ADLATCH;
+                                       pol_l = celltype[9];
                                        pol_r = celltype[10];
                                        srval = celltype[11];
                                } else if (celltype.substr(0, 11) == "$_DLATCHSR_" && celltype.size() == 15 && celltype[14] == '_') {
-                                       ff_type[0] = FF_DLATCHSR;
-                                       pol_e = celltype[11];
+                                       ff_type = FF_DLATCHSR;
+                                       pol_l = celltype[11];
                                        pol_s = celltype[12];
                                        pol_r = celltype[13];
                                } else {
@@ -1197,9 +1127,10 @@ unrecognized:
                                int match = 0;
                                for (auto pair : {
                                        std::make_pair(pol_c, NEG_C),
-                                       std::make_pair(pol_e, NEG_E),
+                                       std::make_pair(pol_l, NEG_L),
                                        std::make_pair(pol_s, NEG_S),
                                        std::make_pair(pol_r, NEG_R),
+                                       std::make_pair(pol_ce, NEG_CE),
                                }) {
                                        if (pair.first == 'N') {
                                                mask |= pair.second;
@@ -1210,40 +1141,33 @@ unrecognized:
                                                goto unrecognized;
                                        }
                                }
+                               int initmask;
+                               if (inittype == "x") {
+                                       initmask = 0x111;
+                               } else if (inittype == "0") {
+                                       initmask = 0x333;
+                               } else if (inittype == "1") {
+                                       initmask = 0x555;
+                               } else if (inittype == "r") {
+                                       if (srval == 0)
+                                               log_error("init type r not valid for cell type %s.\n", celltype.c_str());
+                                       initmask = 0x537;
+                               } else if (inittype == "01") {
+                                       initmask = 0x777;
+                               } else {
+                                       log_error("unrecognized init type %s for cell type %s.\n", inittype.c_str(), celltype.c_str());
+                               }
                                if (srval == '0') {
-                                       ff_type[1] = NUM_FFTYPES;
+                                       initmask &= 0x0ff;
                                } else if (srval == '1') {
-                                       ff_type[0] = NUM_FFTYPES;
+                                       initmask &= 0xf0f;
                                } else if (srval != 0 && srval != '?') {
                                        goto unrecognized;
                                }
-                               for (int i = 0; i < 2; i++) {
-                                       if (ff_type[i] == NUM_FFTYPES)
-                                               continue;
-                                       int initmask;
-                                       if (inittype == "x") {
-                                               initmask = INIT_X;
-                                       } else if (inittype == "0") {
-                                               initmask = INIT_X | INIT_0;
-                                       } else if (inittype == "1") {
-                                               initmask = INIT_X | INIT_1;
-                                       } else if (inittype == "r") {
-                                               if (srval == 0)
-                                                       log_error("init type r not valid for cell type %s.\n", celltype.c_str());
-                                               if (i == 0)
-                                                       initmask = INIT_X | INIT_0;
-                                               else
-                                                       initmask = INIT_X | INIT_1;
-                                       } else if (inittype == "01") {
-                                               initmask = INIT_X | INIT_0 | INIT_1;
-                                       } else {
-                                               log_error("unrecognized init type %s for cell type %s.\n", inittype.c_str(), celltype.c_str());
-                                       }
-                                       for (int neg = 0; neg < NUM_NEG; neg++)
-                                               if ((neg & mask) == match)
-                                                       supported_cells_neg[ff_type[i]][neg] |= initmask;
-                                       supported_cells[ff_type[i]] |= initmask;
-                               }
+                               for (int neg = 0; neg < NUM_NEG; neg++)
+                                       if ((neg & mask) == match)
+                                               supported_cells_neg[ff_type][neg] |= initmask;
+                               supported_cells[ff_type] |= initmask;
                                continue;
                        } else if (args[argidx] == "-mince" && argidx + 1 < args.size()) {
                                mince = atoi(args[++argidx].c_str());
@@ -1256,13 +1180,21 @@ unrecognized:
                }
                extra_args(args, argidx, design);
                supported_dffsr = supported_cells[FF_DFFSR] | supported_cells[FF_DFFSRE];
-               supported_adff0 = supported_cells[FF_ADFF0] | supported_cells[FF_ADFFE0] | supported_dffsr;
-               supported_adff1 = supported_cells[FF_ADFF1] | supported_cells[FF_ADFFE1] | supported_dffsr;
-               supported_sdff0 = supported_cells[FF_SDFF0] | supported_cells[FF_SDFFE0] | supported_cells[FF_SDFFCE0];
-               supported_sdff1 = supported_cells[FF_SDFF1] | supported_cells[FF_SDFFE1] | supported_cells[FF_SDFFCE1];
-               supported_dff = supported_cells[FF_DFF] | supported_cells[FF_DFFE] | supported_dffsr | supported_adff0 | supported_adff1 | supported_sdff0 | supported_sdff1;
-               supported_sr = supported_dffsr | supported_cells[FF_DLATCHSR] | supported_cells[FF_SR] | supported_cells[FF_ADLATCH0] | flip_initmask(supported_cells[FF_ADLATCH1]);
-               supported_dlatch = supported_cells[FF_DLATCH] | supported_cells[FF_ADLATCH0] | supported_cells[FF_ADLATCH1] | supported_cells[FF_DLATCHSR];
+               supported_aldff = supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE] | supported_dffsr;
+               supported_aldffe = supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE];
+               supported_adff = supported_cells[FF_ADFF] | supported_cells[FF_ADFFE] | supported_dffsr | supported_aldff;
+               supported_adffe = supported_cells[FF_ADFFE] | supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE];
+               supported_sdff = supported_cells[FF_SDFF] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE];
+               supported_dff = supported_cells[FF_DFF] | supported_cells[FF_DFFE] | supported_adff | supported_sdff;
+               supported_dffe = supported_cells[FF_DFFE] | supported_cells[FF_DFFSRE] | supported_cells[FF_ALDFFE] | supported_cells[FF_ADFFE] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE];
+               supported_sr_plain = supported_dffsr | supported_cells[FF_DLATCHSR] | supported_cells[FF_SR];
+               supported_sr = supported_sr_plain;
+               supported_sr |= (supported_cells[FF_ADLATCH] >> 4 & 7) * 0x111;
+               supported_sr |= (flip_initmask(supported_cells[FF_ADLATCH]) >> 4 & 7) * 0x111;
+               supported_dlatch_plain = supported_cells[FF_DLATCH] | supported_cells[FF_ADLATCH] | supported_cells[FF_DLATCHSR] | supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE];
+               supported_dlatch = supported_dlatch_plain | supported_sr_plain;
+               supported_rlatch = supported_adff | (supported_dlatch & 7) * 0x111;
+               supported_adlatch = supported_cells[FF_ADLATCH] | supported_cells[FF_DLATCHSR];
 
                for (auto module : design->selected_modules())
                {
@@ -1277,36 +1209,20 @@ unrecognized:
                                        if (!RTLIL::builtin_ff_cell_types().count(cell->type))
                                                continue;
 
-                                       if (cell->hasPort(ID::C) && cell->hasPort(ID::E)) {
-                                               SigSpec sig = cell->getPort(ID::E);
-                                               // Do not count const enable signals.
-                                               if (GetSize(sig) == 1 && sig[0].wire)
-                                                       ce_used[sig[0]]++;
-                                       }
-                                       if (cell->type.str().substr(0, 6) == "$_SDFF") {
-                                               SigSpec sig = cell->getPort(ID::R);
-                                               // Do not count const srst signals.
-                                               if (GetSize(sig) == 1 && sig[0].wire)
-                                                       srst_used[sig[0]]++;
-                                       }
+                                       FfData ff(&initvals, cell);
+                                       if (ff.has_ce && ff.sig_ce[0].wire)
+                                               ce_used[ff.sig_ce[0]] += ff.width;
+                                       if (ff.has_srst && ff.sig_srst[0].wire)
+                                               srst_used[ff.sig_srst[0]] += ff.width;
                                }
                        }
-
-                       // First gather FF cells, then iterate over them later.
-                       // We may need to split an FF into several cells.
-                       std::vector<Cell *> ff_cells;
-
                        for (auto cell : module->selected_cells())
                        {
-                               // Early exit for non-FFs.
                                if (!RTLIL::builtin_ff_cell_types().count(cell->type))
                                        continue;
-
-                               ff_cells.push_back(cell);
+                               FfData ff(&initvals, cell);
+                               legalize_ff(ff);
                        }
-
-                       for (auto cell: ff_cells)
-                               handle_ff(cell);
                }
 
                sigmap.clear();
index 7764e15a5fbe305c44eadbb379756611f68a6c2d..27798ac52409a451ce5324a82d6c839e2ffa577e 100644 (file)
@@ -144,9 +144,9 @@ design -load orig
 dfflegalize -cell $_DFFE_PP0P_ 0 -cell $_DLATCH_P_ 1
 
 select -assert-count 2 adff0/t:$_NOT_
-select -assert-count 16 adff1/t:$_NOT_
+select -assert-count 13 adff1/t:$_NOT_
 select -assert-count 3 adffe0/t:$_NOT_
-select -assert-count 22 adffe1/t:$_NOT_
+select -assert-count 18 adffe1/t:$_NOT_
 select -assert-count 0 adff0/t:$_MUX_
 select -assert-count 3 adff1/t:$_MUX_
 select -assert-count 0 adffe0/t:$_MUX_
@@ -164,9 +164,9 @@ select -assert-none t:$_DFFE_PP0P_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t
 design -load orig
 dfflegalize -cell $_DFFE_PP0P_ 1 -cell $_DLATCH_P_ 1
 
-select -assert-count 16 adff0/t:$_NOT_
+select -assert-count 13 adff0/t:$_NOT_
 select -assert-count 8 adff1/t:$_NOT_
-select -assert-count 22 adffe0/t:$_NOT_
+select -assert-count 18 adffe0/t:$_NOT_
 select -assert-count 11 adffe1/t:$_NOT_
 select -assert-count 3 adff0/t:$_MUX_
 select -assert-count 0 adff1/t:$_MUX_
@@ -185,31 +185,27 @@ select -assert-none t:$_DFFE_PP0P_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t
 design -load orig
 dfflegalize -cell $_DFFE_PP1P_ 0 -cell $_DLATCH_P_ 1
 
-select -assert-count 16 adff0/t:$_NOT_
+select -assert-count 10 adff0/t:$_NOT_
 select -assert-count 2 adff1/t:$_NOT_
-select -assert-count 22 adffe0/t:$_NOT_
+select -assert-count 14 adffe0/t:$_NOT_
 select -assert-count 3 adffe1/t:$_NOT_
 select -assert-count 3 adff0/t:$_MUX_
 select -assert-count 0 adff1/t:$_MUX_
 select -assert-count 4 adffe0/t:$_MUX_
 select -assert-count 0 adffe1/t:$_MUX_
-select -assert-count 6 adff0/t:$_DFFE_PP1P_
+select -assert-count 9 adff0/t:$_DFFE_PP1P_
 select -assert-count 3 adff1/t:$_DFFE_PP1P_
-select -assert-count 8 adffe0/t:$_DFFE_PP1P_
+select -assert-count 12 adffe0/t:$_DFFE_PP1P_
 select -assert-count 4 adffe1/t:$_DFFE_PP1P_
-select -assert-count 3 adff0/t:$_DLATCH_P_
-select -assert-count 0 adff1/t:$_DLATCH_P_
-select -assert-count 4 adffe0/t:$_DLATCH_P_
-select -assert-count 0 adffe1/t:$_DLATCH_P_
-select -assert-none t:$_DFFE_PP1P_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+select -assert-none t:$_DFFE_PP1P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
 
 design -load orig
 dfflegalize -cell $_DFFE_PP1P_ 1 -cell $_DLATCH_P_ 1
 
 select -assert-count 8 adff0/t:$_NOT_
-select -assert-count 16 adff1/t:$_NOT_
+select -assert-count 13 adff1/t:$_NOT_
 select -assert-count 11 adffe0/t:$_NOT_
-select -assert-count 22 adffe1/t:$_NOT_
+select -assert-count 18 adffe1/t:$_NOT_
 select -assert-count 0 adff0/t:$_MUX_
 select -assert-count 3 adff1/t:$_MUX_
 select -assert-count 0 adffe0/t:$_MUX_
index 7b22ea0c0b08393af2ff76f147e5728674dd1aa4..a55082d1d53c880c87627a111fb4030c4700c4df 100644 (file)
@@ -45,7 +45,7 @@ select -assert-none t:$_DLATCH_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
 design -load orig
 dfflegalize -cell $_DLATCH_PP0_ 1
 
-select -assert-count 16 adlatch0/t:$_NOT_
+select -assert-count 13 adlatch0/t:$_NOT_
 select -assert-count 8 adlatch1/t:$_NOT_
 select -assert-count 3 adlatch0/t:$_MUX_
 select -assert-count 0 adlatch1/t:$_MUX_
@@ -68,7 +68,7 @@ design -load orig
 dfflegalize -cell $_DLATCH_PP1_ 1
 
 select -assert-count 8 adlatch0/t:$_NOT_
-select -assert-count 16 adlatch1/t:$_NOT_
+select -assert-count 13 adlatch1/t:$_NOT_
 select -assert-count 0 adlatch0/t:$_MUX_
 select -assert-count 3 adlatch1/t:$_MUX_
 select -assert-count 3 adlatch0/t:$_DLATCH_PP1_
index 63ab478652cd66582a34979a9795097bc8fd2250..4022da5f450dc9de3ceadb0a464d39889fab45d6 100644 (file)
@@ -237,25 +237,18 @@ select -assert-count 2 sdff0/t:$_NOT_
 select -assert-count 8 sdff1/t:$_NOT_
 select -assert-count 2 sdffe0/t:$_NOT_
 select -assert-count 10 sdffe1/t:$_NOT_
-select -assert-count 2 sdffce0/t:$_NOT_
-select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
 select -assert-count 0 dff/t:$_MUX_
 select -assert-count 3 dffe/t:$_MUX_
 select -assert-count 0 sdff0/t:$_MUX_
 select -assert-count 0 sdff1/t:$_MUX_
 select -assert-count 4 sdffe0/t:$_MUX_
 select -assert-count 4 sdffe1/t:$_MUX_
-select -assert-count 4 sdffce0/t:$_MUX_
-select -assert-count 4 sdffce1/t:$_MUX_
-select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* sdffce1/* %u %n %i
-select -assert-count 2 sdffce0/t:$_AND_
-select -assert-count 2 sdffce1/t:$_AND_
-select -assert-count 1 sdffce0/t:$_ORNOT_
-select -assert-count 1 sdffce1/t:$_ORNOT_
-select -assert-count 1 sdffce0/t:$_ANDNOT_
-select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
 select -assert-count 27 t:$_SDFF_PP0_
-select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
 
 
 # Convert everything to SDFFEs.
index 741ac39d0c846fd9b0edc3ab16f523699f51b39a..ccde4c32410cebd93f716642d44196481ec7ac99 100644 (file)
@@ -476,7 +476,7 @@ select -assert-count 2 sdff0/t:$_NOT_
 select -assert-count 1 sdff1/t:$_NOT_
 select -assert-count 2 sdffe0/t:$_NOT_
 select -assert-count 1 sdffe1/t:$_NOT_
-select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
 select -assert-count 1 sdffce1/t:$_NOT_
 select -assert-count 0 dff/t:$_MUX_
 select -assert-count 3 dffe/t:$_MUX_
@@ -484,14 +484,10 @@ select -assert-count 0 sdff0/t:$_MUX_
 select -assert-count 3 sdff1/t:$_MUX_
 select -assert-count 4 sdffe0/t:$_MUX_
 select -assert-count 8 sdffe1/t:$_MUX_
-select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
 select -assert-count 8 sdffce1/t:$_MUX_
-select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* %n %i
-select -assert-count 2 sdffce0/t:$_AND_
-select -assert-count 1 sdffce0/t:$_ORNOT_
-select -assert-count 1 sdffce0/t:$_ANDNOT_
 select -assert-count 27 t:$_SDFF_PP0_
-select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
 
 design -load orig
 dfflegalize -cell $_SDFF_PP0_ 1
@@ -503,7 +499,7 @@ select -assert-count 8 sdff1/t:$_NOT_
 select -assert-count 9 sdffe0/t:$_NOT_
 select -assert-count 10 sdffe1/t:$_NOT_
 select -assert-count 9 sdffce0/t:$_NOT_
-select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 9 sdffce1/t:$_NOT_
 select -assert-count 0 dff/t:$_MUX_
 select -assert-count 3 dffe/t:$_MUX_
 select -assert-count 3 sdff0/t:$_MUX_
@@ -511,13 +507,9 @@ select -assert-count 0 sdff1/t:$_MUX_
 select -assert-count 8 sdffe0/t:$_MUX_
 select -assert-count 4 sdffe1/t:$_MUX_
 select -assert-count 8 sdffce0/t:$_MUX_
-select -assert-count 4 sdffce1/t:$_MUX_
-select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce1/* %n %i
-select -assert-count 2 sdffce1/t:$_AND_
-select -assert-count 1 sdffce1/t:$_ORNOT_
-select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 8 sdffce1/t:$_MUX_
 select -assert-count 27 t:$_SDFF_PP0_
-select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
 
 design -load orig
 dfflegalize -cell $_SDFF_PP1_ 0
@@ -529,7 +521,7 @@ select -assert-count 2 sdff1/t:$_NOT_
 select -assert-count 1 sdffe0/t:$_NOT_
 select -assert-count 2 sdffe1/t:$_NOT_
 select -assert-count 1 sdffce0/t:$_NOT_
-select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
 select -assert-count 0 dff/t:$_MUX_
 select -assert-count 3 dffe/t:$_MUX_
 select -assert-count 3 sdff0/t:$_MUX_
@@ -537,13 +529,9 @@ select -assert-count 0 sdff1/t:$_MUX_
 select -assert-count 8 sdffe0/t:$_MUX_
 select -assert-count 4 sdffe1/t:$_MUX_
 select -assert-count 8 sdffce0/t:$_MUX_
-select -assert-count 4 sdffce1/t:$_MUX_
-select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce1/* %n %i
-select -assert-count 2 sdffce1/t:$_AND_
-select -assert-count 1 sdffce1/t:$_ORNOT_
-select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 8 sdffce1/t:$_MUX_
 select -assert-count 27 t:$_SDFF_PP1_
-select -assert-none t:$_SDFF_PP1_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+select -assert-none t:$_SDFF_PP1_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
 
 design -load orig
 dfflegalize -cell $_SDFF_PP1_ 1
@@ -554,7 +542,7 @@ select -assert-count 8 sdff0/t:$_NOT_
 select -assert-count 7 sdff1/t:$_NOT_
 select -assert-count 10 sdffe0/t:$_NOT_
 select -assert-count 9 sdffe1/t:$_NOT_
-select -assert-count 10 sdffce0/t:$_NOT_
+select -assert-count 9 sdffce0/t:$_NOT_
 select -assert-count 9 sdffce1/t:$_NOT_
 select -assert-count 0 dff/t:$_MUX_
 select -assert-count 3 dffe/t:$_MUX_
@@ -562,14 +550,10 @@ select -assert-count 0 sdff0/t:$_MUX_
 select -assert-count 3 sdff1/t:$_MUX_
 select -assert-count 4 sdffe0/t:$_MUX_
 select -assert-count 8 sdffe1/t:$_MUX_
-select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
 select -assert-count 8 sdffce1/t:$_MUX_
-select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* %n %i
-select -assert-count 2 sdffce0/t:$_AND_
-select -assert-count 1 sdffce0/t:$_ORNOT_
-select -assert-count 1 sdffce0/t:$_ANDNOT_
 select -assert-count 27 t:$_SDFF_PP1_
-select -assert-none t:$_SDFF_PP1_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+select -assert-none t:$_SDFF_PP1_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
 
 
 # Convert everything to SDFFEs.
index f30a534fde353966c718f1038e6f32c1c1b4c59b..1596922490a159b0800db626318ccb7cdf345bc6 100644 (file)
@@ -24,14 +24,14 @@ equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 1
 design -load orig
 dfflegalize -cell $_DFF_PP0_ 01
 
-select -assert-count 12 t:$_NOT_
+select -assert-count 8 t:$_NOT_
 select -assert-count 8 t:$_DFF_PP0_
 select -assert-none t:$_DFF_PP0_ t:$_NOT_ %% %n t:* %i
 
 design -load orig
 dfflegalize -cell $_DFF_PP?_ 0
 
-select -assert-count 12 t:$_NOT_
+select -assert-count 8 t:$_NOT_
 select -assert-count 4 t:$_DFF_PP0_
 select -assert-count 4 t:$_DFF_PP1_
 select -assert-none t:$_DFF_PP0_ t:$_DFF_PP1_ t:$_NOT_ %% %n t:* %i
@@ -41,13 +41,13 @@ select -assert-none t:$_DFF_PP0_ t:$_DFF_PP1_ t:$_NOT_ %% %n t:* %i
 design -load orig
 dfflegalize -cell $_DFFSRE_PPPP_ 0
 
-select -assert-count 12 t:$_NOT_
+select -assert-count 8 t:$_NOT_
 select -assert-count 8 t:$_DFFSRE_PPPP_
 select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ %% %n t:* %i
 
 design -load orig
 dfflegalize -cell $_DFFSRE_PPPP_ 1
 
-select -assert-count 12 t:$_NOT_
+select -assert-count 8 t:$_NOT_
 select -assert-count 8 t:$_DFFSRE_PPPP_
 select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ %% %n t:* %i
index 2d33634d17285109d35ed67934e69cc6ecb81c82..b38a9eb3b8e90aa7a5e3535f512aac830c8f3706 100644 (file)
@@ -66,8 +66,8 @@ select -assert-none t:$_DLATCH_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_O
 design -load orig
 dfflegalize -cell $_DLATCH_PP1_ 0
 
-select -assert-count 22 dlatchsr0/t:$_NOT_
-select -assert-count 26 dlatchsr1/t:$_NOT_
+select -assert-count 18 dlatchsr0/t:$_NOT_
+select -assert-count 22 dlatchsr1/t:$_NOT_
 select -assert-count 4 dlatchsr0/t:$_MUX_
 select -assert-count 4 dlatchsr1/t:$_MUX_
 select -assert-count 12 dlatchsr0/t:$_DLATCH_PP1_
@@ -81,8 +81,8 @@ select -assert-none t:$_DLATCH_PP1_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_O
 design -load orig
 dfflegalize -cell $_DLATCH_PP1_ 1
 
-select -assert-count 22 dlatchsr0/t:$_NOT_
-select -assert-count 26 dlatchsr1/t:$_NOT_
+select -assert-count 18 dlatchsr0/t:$_NOT_
+select -assert-count 22 dlatchsr1/t:$_NOT_
 select -assert-count 4 dlatchsr0/t:$_MUX_
 select -assert-count 4 dlatchsr1/t:$_MUX_
 select -assert-count 12 dlatchsr0/t:$_DLATCH_PP1_
index 0fc40dc089314d718986adadb403fcedf8be089d..689066147d5d1d828ea20e145b47d3fd65546664 100644 (file)
@@ -23,9 +23,9 @@ design -load postopt
 
 select -assert-count 5 t:$_SDFF_PP0_
 select -assert-count 1 t:$_SDFF_PP1_
-select -assert-count 3 t:$_SDFFE_PP0P_
+select -assert-count 1 t:$_SDFFE_PP0P_
 select -assert-count 1 t:$_SDFFE_PP1P_
-select -assert-count 1 t:$_SDFFCE_PP0P_
+select -assert-count 3 t:$_SDFFCE_PP0P_
 select -assert-count 1 t:$_SDFFCE_PP1P_
 select -assert-count 8 t:$_MUX_
 select -assert-count 0 n:ff0 %ci %ci t:$_MUX_ %i
index 27e83be91960cee3b485d0d42b2851afe019266d..ee59a6e3cf73825740d169ecfec72bbe9f319f4d 100644 (file)
@@ -39,7 +39,7 @@ select -assert-none t:$_DLATCH_PP0_ t:$_NOT_ %% %n t:* %i
 design -load orig
 dfflegalize -cell $_DLATCH_PP1_ x
 
-select -assert-count 8 t:$_NOT_
+select -assert-count 5 t:$_NOT_
 select -assert-count 3 t:$_DLATCH_PP1_
 select -assert-none t:$_DLATCH_PP1_ t:$_NOT_ %% %n t:* %i
 
index 52b797b9ecdb66fc42c84861101feb0fff69012a..9d724de2987b713e9da2726e572ab29a0b05f05b 100644 (file)
@@ -12,7 +12,7 @@ $_SR_PN_ ff1 (.R(R), .S(S), .Q(Q[1]));
 $_SR_NP_ ff2 (.R(R), .S(S), .Q(Q[2]));
 endmodule
 
-module top(input C, E, R, D, output [5:0] Q);
+module top(input R, S, output [5:0] Q);
 sr0 sr0_(.S(S), .R(R), .Q(Q[2:0]));
 sr1 sr1_(.S(S), .R(R), .Q(Q[5:3]));
 endmodule
@@ -103,8 +103,8 @@ select -assert-none t:$_DLATCH_PP0_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/*
 design -load orig
 dfflegalize -cell $_DLATCH_PP1_ 0
 
-select -assert-count 11 sr0/t:$_NOT_
-select -assert-count 8 sr1/t:$_NOT_
+select -assert-count 8 sr0/t:$_NOT_
+select -assert-count 5 sr1/t:$_NOT_
 select -assert-count 3 sr0/t:$_DLATCH_PP1_
 select -assert-count 3 sr1/t:$_DLATCH_PP1_
 select -assert-count 1 sr0/t:$_ANDNOT_
@@ -118,8 +118,8 @@ select -assert-none t:$_DLATCH_PP1_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/*
 design -load orig
 dfflegalize -cell $_DLATCH_PP1_ 1
 
-select -assert-count 8 sr0/t:$_NOT_
-select -assert-count 11 sr1/t:$_NOT_
+select -assert-count 5 sr0/t:$_NOT_
+select -assert-count 8 sr1/t:$_NOT_
 select -assert-count 3 sr0/t:$_DLATCH_PP1_
 select -assert-count 3 sr1/t:$_DLATCH_PP1_
 select -assert-count 0 sr0/t:$_ANDNOT_