kernel/ff: Refactor FfData to enable FFs with async load.
authorMarcelina Kościelnicka <mwk@0x04.net>
Fri, 1 Oct 2021 21:50:48 +0000 (23:50 +0200)
committerMarcelina Kościelnicka <mwk@0x04.net>
Sat, 2 Oct 2021 18:19:48 +0000 (20:19 +0200)
- *_en is split into *_ce (clock enable) and *_aload (async load aka
  latch gate enable), so both can be present at once
- has_d is removed
- has_gclk is added (to have a clear marker for $ff)
- d_is_const and val_d leftovers are removed
- async2sync, clk2fflogic, opt_dff are updated to operate correctly on
  FFs with async load

backends/verilog/verilog_backend.cc
kernel/ff.h
kernel/ffmerge.cc
kernel/mem.cc
kernel/satgen.cc
passes/memory/memory_dff.cc
passes/opt/opt_dff.cc
passes/sat/async2sync.cc
passes/sat/clk2fflogic.cc
passes/techmap/dffunmap.cc

index 47b48a4603980870dac605ea240a816f24d6aea1..6fb14d7fc8455a193fb4ca4c7c6cecbce0274453 100644 (file)
@@ -1398,7 +1398,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                FfData ff(nullptr, cell);
 
                // $ff / $_FF_ cell: not supported.
-               if (ff.has_d && !ff.has_clk && !ff.has_en)
+               if (ff.has_gclk)
                        return false;
 
                std::string reg_name = cellname(cell);
@@ -1419,17 +1419,19 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
 
                for (int i = 0; i < chunks; i++)
                {
-                       SigSpec sig_d;
+                       SigSpec sig_d, sig_ad;
                        Const val_arst, val_srst;
-                       std::string reg_bit_name, sig_set_name, sig_clr_name, sig_arst_name;
+                       std::string reg_bit_name, sig_set_name, sig_clr_name, sig_arst_name, sig_aload_name;
                        if (chunky) {
                                reg_bit_name = stringf("%s[%d]", reg_name.c_str(), i);
-                               if (ff.has_d)
+                               if (ff.has_gclk || ff.has_clk)
                                        sig_d = ff.sig_d[i];
+                               if (ff.has_aload)
+                                       sig_ad = ff.sig_ad[i];
                        } else {
                                reg_bit_name = reg_name;
-                               if (ff.has_d)
-                                       sig_d = ff.sig_d;
+                               sig_d = ff.sig_d;
+                               sig_ad = ff.sig_ad;
                        }
                        if (ff.has_arst)
                                val_arst = chunky ? ff.val_arst[i] : ff.val_arst;
@@ -1437,28 +1439,38 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                                val_srst = chunky ? ff.val_srst[i] : ff.val_srst;
 
                        // If there are constants in the sensitivity list, replace them with an intermediate wire
-                       if (ff.has_sr) {
-                               if (ff.sig_set[i].wire == NULL)
-                               {
-                                       sig_set_name = next_auto_id();
-                                       f << stringf("%s" "wire %s = ", indent.c_str(), sig_set_name.c_str());
-                                       dump_const(f, ff.sig_set[i].data);
-                                       f << stringf(";\n");
-                               }
-                               if (ff.sig_clr[i].wire == NULL)
-                               {
-                                       sig_clr_name = next_auto_id();
-                                       f << stringf("%s" "wire %s = ", indent.c_str(), sig_clr_name.c_str());
-                                       dump_const(f, ff.sig_clr[i].data);
-                                       f << stringf(";\n");
-                               }
-                       } else if (ff.has_arst) {
-                               if (ff.sig_arst[i].wire == NULL)
-                               {
-                                       sig_arst_name = next_auto_id();
-                                       f << stringf("%s" "wire %s = ", indent.c_str(), sig_arst_name.c_str());
-                                       dump_const(f, ff.sig_arst[i].data);
-                                       f << stringf(";\n");
+                       if (ff.has_clk) {
+                               if (ff.has_sr) {
+                                       if (ff.sig_set[i].wire == NULL)
+                                       {
+                                               sig_set_name = next_auto_id();
+                                               f << stringf("%s" "wire %s = ", indent.c_str(), sig_set_name.c_str());
+                                               dump_const(f, ff.sig_set[i].data);
+                                               f << stringf(";\n");
+                                       }
+                                       if (ff.sig_clr[i].wire == NULL)
+                                       {
+                                               sig_clr_name = next_auto_id();
+                                               f << stringf("%s" "wire %s = ", indent.c_str(), sig_clr_name.c_str());
+                                               dump_const(f, ff.sig_clr[i].data);
+                                               f << stringf(";\n");
+                                       }
+                               } else if (ff.has_arst) {
+                                       if (ff.sig_arst[0].wire == NULL)
+                                       {
+                                               sig_arst_name = next_auto_id();
+                                               f << stringf("%s" "wire %s = ", indent.c_str(), sig_arst_name.c_str());
+                                               dump_const(f, ff.sig_arst[0].data);
+                                               f << stringf(";\n");
+                                       }
+                               } else if (ff.has_aload) {
+                                       if (ff.sig_aload[0].wire == NULL)
+                                       {
+                                               sig_aload_name = next_auto_id();
+                                               f << stringf("%s" "wire %s = ", indent.c_str(), sig_aload_name.c_str());
+                                               dump_const(f, ff.sig_aload[0].data);
+                                               f << stringf(";\n");
+                                       }
                                }
                        }
 
@@ -1480,13 +1492,18 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                                                f << stringf("%s", sig_clr_name.c_str());
                                        else
                                                dump_sigspec(f, ff.sig_clr[i]);
-
                                } else if (ff.has_arst) {
                                        f << stringf(", %sedge ", ff.pol_arst ? "pos" : "neg");
-                                       if (ff.sig_arst[i].wire == NULL)
+                                       if (ff.sig_arst[0].wire == NULL)
                                                f << stringf("%s", sig_arst_name.c_str());
                                        else
                                                dump_sigspec(f, ff.sig_arst);
+                               } else if (ff.has_aload) {
+                                       f << stringf(", %sedge ", ff.pol_aload ? "pos" : "neg");
+                                       if (ff.sig_aload[0].wire == NULL)
+                                               f << stringf("%s", sig_aload_name.c_str());
+                                       else
+                                               dump_sigspec(f, ff.sig_aload);
                                }
                                f << stringf(")\n");
 
@@ -1507,7 +1524,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                                        f << stringf("%s" "  else ", indent.c_str());
                                } else if (ff.has_arst) {
                                        f << stringf("if (%s", ff.pol_arst ? "" : "!");
-                                       if (ff.sig_arst[i].wire == NULL)
+                                       if (ff.sig_arst[0].wire == NULL)
                                                f << stringf("%s", sig_arst_name.c_str());
                                        else
                                                dump_sigspec(f, ff.sig_arst);
@@ -1515,11 +1532,21 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                                        dump_sigspec(f, val_arst);
                                        f << stringf(";\n");
                                        f << stringf("%s" "  else ", indent.c_str());
+                               } else if (ff.has_aload) {
+                                       f << stringf("if (%s", ff.pol_aload ? "" : "!");
+                                       if (ff.sig_aload[0].wire == NULL)
+                                               f << stringf("%s", sig_aload_name.c_str());
+                                       else
+                                               dump_sigspec(f, ff.sig_aload);
+                                       f << stringf(") %s <= ", reg_bit_name.c_str());
+                                       dump_sigspec(f, sig_ad);
+                                       f << stringf(";\n");
+                                       f << stringf("%s" "  else ", indent.c_str());
                                }
 
-                               if (ff.has_srst && ff.has_en && ff.ce_over_srst) {
-                                       f << stringf("if (%s", ff.pol_en ? "" : "!");
-                                       dump_sigspec(f, ff.sig_en);
+                               if (ff.has_srst && ff.has_ce && ff.ce_over_srst) {
+                                       f << stringf("if (%s", ff.pol_ce ? "" : "!");
+                                       dump_sigspec(f, ff.sig_ce);
                                        f << stringf(")\n");
                                        f << stringf("%s" "    if (%s", indent.c_str(), ff.pol_srst ? "" : "!");
                                        dump_sigspec(f, ff.sig_srst);
@@ -1536,9 +1563,9 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                                                f << stringf(";\n");
                                                f << stringf("%s" "  else ", indent.c_str());
                                        }
-                                       if (ff.has_en) {
-                                               f << stringf("if (%s", ff.pol_en ? "" : "!");
-                                               dump_sigspec(f, ff.sig_en);
+                                       if (ff.has_ce) {
+                                               f << stringf("if (%s", ff.pol_ce ? "" : "!");
+                                               dump_sigspec(f, ff.sig_ce);
                                                f << stringf(") ");
                                        }
                                }
@@ -1560,7 +1587,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                                        f << stringf("%s" "  else if (%s", indent.c_str(), ff.pol_set ? "" : "!");
                                        dump_sigspec(f, ff.sig_set[i]);
                                        f << stringf(") %s = 1'b1;\n", reg_bit_name.c_str());
-                                       if (ff.has_d)
+                                       if (ff.has_aload)
                                                f << stringf("%s" "  else ", indent.c_str());
                                } else if (ff.has_arst) {
                                        f << stringf("if (%s", ff.pol_arst ? "" : "!");
@@ -1568,14 +1595,14 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                                        f << stringf(") %s = ", reg_bit_name.c_str());
                                        dump_sigspec(f, val_arst);
                                        f << stringf(";\n");
-                                       if (ff.has_d)
+                                       if (ff.has_aload)
                                                f << stringf("%s" "  else ", indent.c_str());
                                }
-                               if (ff.has_d) {
-                                       f << stringf("if (%s", ff.pol_en ? "" : "!");
-                                       dump_sigspec(f, ff.sig_en);
+                               if (ff.has_aload) {
+                                       f << stringf("if (%s", ff.pol_aload ? "" : "!");
+                                       dump_sigspec(f, ff.sig_aload);
                                        f << stringf(") %s = ", reg_bit_name.c_str());
-                                       dump_sigspec(f, sig_d);
+                                       dump_sigspec(f, sig_ad);
                                        f << stringf(";\n");
                                }
                        }
index e555e15f1e678179fbfab2a099592e03aec8bb96..a06eb0a1c839028597bf5a67527be1a9f6de98db 100644 (file)
 
 YOSYS_NAMESPACE_BEGIN
 
+// Describes a flip-flop or a latch.
+//
+// If has_gclk, this is a formal verification FF with implicit global clock:
+// Q is simply previous cycle's D.
+//
+// Otherwise, the FF/latch can have any number of features selected by has_*
+// attributes that determine Q's value (in order of decreasing priority):
+//
+// - on start, register is initialized to val_init
+// - if has_sr is present:
+//   - sig_clr is per-bit async clear, and sets the corresponding bit to 0
+//     if active
+//   - sig_set is per-bit async set, and sets the corresponding bit to 1
+//     if active
+// - if has_arst is present:
+//   - sig_arst is whole-reg async reset, and sets the whole register to val_arst
+// - if has_aload is present:
+//   - sig_aload is whole-reg async load (aka latch gate enable), and sets the whole
+//     register to sig_ad
+// - if has_clk is present, and we're currently on a clock edge:
+//   - if has_ce is present and ce_over_srst is true:
+//     - ignore clock edge (don't change value) unless sig_ce is active
+//   - if has_srst is present:
+//     - sig_srst is whole-reg sync reset and sets the register to val_srst
+//   - if has_ce is present and ce_over_srst is false:
+//     - ignore clock edge (don't change value) unless sig_ce is active
+//   - set whole reg to sig_d
+// - if nothing of the above applies, the reg value remains unchanged
+//
+// Since the yosys FF cell library isn't fully generic, not all combinations
+// of the features above can be supported:
+//
+// - only one of has_srst, has_arst, has_sr can be used
+// - if has_clk is used together with has_aload, then has_srst, has_arst,
+//   has_sr cannot be used
+//
+// The valid feature combinations are thus:
+//
+// - has_clk + optional has_ce [dff/dffe]
+// - has_clk + optional has_ce + has_arst [adff/adffe]
+// - has_clk + optional has_ce + has_aload [aldff/aldffe]
+// - has_clk + optional has_ce + has_sr [dffsr/dffsre]
+// - has_clk + optional has_ce + has_srst [sdff/sdffe/sdffce]
+// - has_aload [dlatch]
+// - has_aload + has_arst [adlatch]
+// - has_aload + has_sr [dlatchsr]
+// - has_sr [sr]
+// - has_arst [does not correspond to a native cell, represented as dlatch with const D input]
+// - empty set [not a cell — will be emitted as a simple direct connection]
+
 struct FfData {
        FfInitVals *initvals;
+       // The FF output.
        SigSpec sig_q;
+       // The sync data input, present if has_clk or has_gclk.
        SigSpec sig_d;
+       // The async data input, present if has_aload.
+       SigSpec sig_ad;
+       // The sync clock, present if has_clk.
        SigSpec sig_clk;
-       SigSpec sig_en;
+       // The clock enable, present if has_ce.
+       SigSpec sig_ce;
+       // The async load enable, present if has_aload.
+       SigSpec sig_aload;
+       // The async reset, preset if has_arst.
        SigSpec sig_arst;
+       // The sync reset, preset if has_srst.
        SigSpec sig_srst;
+       // The async clear (per-lane), present if has_sr.
        SigSpec sig_clr;
+       // The async set (per-lane), present if has_sr.
        SigSpec sig_set;
-       bool has_d;
+       // True if this is a clocked (edge-sensitive) flip-flop.
        bool has_clk;
-       bool has_en;
+       // True if this is a $ff, exclusive with every other has_*.
+       bool has_gclk;
+       // True if this FF has a clock enable.  Depends on has_clk.
+       bool has_ce;
+       // True if this FF has async load function — this includes D latches.
+       // If this and has_clk are both set, has_arst and has_sr cannot be set.
+       bool has_aload;
+       // True if this FF has sync set/reset.  Depends on has_clk, exclusive
+       // with has_arst, has_sr, has_aload.
        bool has_srst;
+       // True if this FF has async set/reset.  Exclusive with has_srst,
+       // has_sr.  If this and has_clk are both set, has_aload cannot be set.
        bool has_arst;
+       // True if this FF has per-bit async set + clear.  Exclusive with
+       // has_srst, has_arst.  If this and has_clk are both set, has_aload
+       // cannot be set.
        bool has_sr;
+       // If has_ce and has_srst are both set, determines their relative
+       // priorities: if true, inactive ce disables srst; if false, srst
+       // operates independent of ce.
        bool ce_over_srst;
+       // True if this FF is a fine cell, false if it is a coarse cell.
+       // If true, width must be 1.
        bool is_fine;
+       // Polarities, corresponding to sig_*.  True means active-high, false
+       // means active-low.
        bool pol_clk;
-       bool pol_en;
+       bool pol_ce;
+       bool pol_aload;
        bool pol_arst;
        bool pol_srst;
        bool pol_clr;
        bool pol_set;
+       // The value loaded by sig_arst.
        Const val_arst;
+       // The value loaded by sig_srst.
        Const val_srst;
+       // The initial value at power-up.
        Const val_init;
-       Const val_d;
-       bool d_is_const;
+       // The FF data width in bits.
        int width;
        dict<IdString, Const> attributes;
 
        FfData(FfInitVals *initvals = nullptr, Cell *cell = nullptr) : initvals(initvals) {
                width = 0;
-               has_d = true;
                has_clk = false;
-               has_en = false;
+               has_gclk = false;
+               has_ce = false;
+               has_aload = false;
                has_srst = false;
                has_arst = false;
                has_sr = false;
                ce_over_srst = false;
                is_fine = false;
                pol_clk = false;
-               pol_en = false;
+               pol_aload = false;
+               pol_ce = false;
                pol_arst = false;
                pol_srst = false;
                pol_clr = false;
                pol_set = false;
-               d_is_const = false;
 
                if (!cell)
                        return;
@@ -88,20 +174,26 @@ struct FfData {
                std::string type_str = cell->type.str();
 
                if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
-                       if (cell->type == ID($sr)) {
-                               has_d = false;
-                       } else {
+                       if (cell->type == ID($ff)) {
+                               has_gclk = true;
                                sig_d = cell->getPort(ID::D);
-                       }
-                       if (!cell->type.in(ID($ff), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
+                       } else if (cell->type == ID($sr)) {
+                               // No data input at all.
+                       } else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
+                               has_aload = true;
+                               sig_aload = cell->getPort(ID::EN);
+                               pol_aload = cell->getParam(ID::EN_POLARITY).as_bool();
+                               sig_ad = cell->getPort(ID::D);
+                       } else {
                                has_clk = true;
                                sig_clk = cell->getPort(ID::CLK);
                                pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
+                               sig_d = cell->getPort(ID::D);
                        }
-                       if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr))) {
-                               has_en = true;
-                               sig_en = cell->getPort(ID::EN);
-                               pol_en = cell->getParam(ID::EN_POLARITY).as_bool();
+                       if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($sdffe), ID($sdffce))) {
+                               has_ce = true;
+                               sig_ce = cell->getPort(ID::EN);
+                               pol_ce = cell->getParam(ID::EN_POLARITY).as_bool();
                        }
                        if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) {
                                has_sr = true;
@@ -125,10 +217,10 @@ struct FfData {
                        }
                } else if (cell->type == ID($_FF_)) {
                        is_fine = true;
+                       has_gclk = true;
                        sig_d = cell->getPort(ID::D);
                } else if (type_str.substr(0, 5) == "$_SR_") {
                        is_fine = true;
-                       has_d = false;
                        has_sr = true;
                        pol_set = type_str[5] == 'P';
                        pol_clr = type_str[6] == 'P';
@@ -146,9 +238,9 @@ struct FfData {
                        has_clk = true;
                        pol_clk = type_str[7] == 'P';
                        sig_clk = cell->getPort(ID::C);
-                       has_en = true;
-                       pol_en = type_str[8] == 'P';
-                       sig_en = cell->getPort(ID::E);
+                       has_ce = true;
+                       pol_ce = type_str[8] == 'P';
+                       sig_ce = cell->getPort(ID::E);
                } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
                        is_fine = true;
                        sig_d = cell->getPort(ID::D);
@@ -169,9 +261,9 @@ struct FfData {
                        pol_arst = type_str[8] == 'P';
                        sig_arst = cell->getPort(ID::R);
                        val_arst = type_str[9] == '1' ? State::S1 : State::S0;
-                       has_en = true;
-                       pol_en = type_str[10] == 'P';
-                       sig_en = cell->getPort(ID::E);
+                       has_ce = true;
+                       pol_ce = type_str[10] == 'P';
+                       sig_ce = cell->getPort(ID::E);
                } else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
                        is_fine = true;
                        sig_d = cell->getPort(ID::D);
@@ -194,9 +286,9 @@ struct FfData {
                        pol_clr = type_str[11] == 'P';
                        sig_set = cell->getPort(ID::S);
                        sig_clr = cell->getPort(ID::R);
-                       has_en = true;
-                       pol_en = type_str[12] == 'P';
-                       sig_en = cell->getPort(ID::E);
+                       has_ce = true;
+                       pol_ce = type_str[12] == 'P';
+                       sig_ce = cell->getPort(ID::E);
                } else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
                        is_fine = true;
                        sig_d = cell->getPort(ID::D);
@@ -217,9 +309,9 @@ struct FfData {
                        pol_srst = type_str[9] == 'P';
                        sig_srst = cell->getPort(ID::R);
                        val_srst = type_str[10] == '1' ? State::S1 : State::S0;
-                       has_en = true;
-                       pol_en = type_str[11] == 'P';
-                       sig_en = cell->getPort(ID::E);
+                       has_ce = true;
+                       pol_ce = type_str[11] == 'P';
+                       sig_ce = cell->getPort(ID::E);
                } else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
                        is_fine = true;
                        sig_d = cell->getPort(ID::D);
@@ -230,32 +322,35 @@ struct FfData {
                        pol_srst = type_str[10] == 'P';
                        sig_srst = cell->getPort(ID::R);
                        val_srst = type_str[11] == '1' ? State::S1 : State::S0;
-                       has_en = true;
-                       pol_en = type_str[12] == 'P';
-                       sig_en = cell->getPort(ID::E);
+                       has_ce = true;
+                       pol_ce = type_str[12] == 'P';
+                       sig_ce = cell->getPort(ID::E);
                        ce_over_srst = true;
                } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
                        is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_en = true;
-                       pol_en = type_str[9] == 'P';
-                       sig_en = cell->getPort(ID::E);
+                       has_aload = true;
+                       sig_ad = cell->getPort(ID::D);
+                       has_aload = true;
+                       pol_aload = type_str[9] == 'P';
+                       sig_aload = cell->getPort(ID::E);
                } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
                        is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_en = true;
-                       pol_en = type_str[9] == 'P';
-                       sig_en = cell->getPort(ID::E);
+                       has_aload = true;
+                       sig_ad = cell->getPort(ID::D);
+                       has_aload = true;
+                       pol_aload = type_str[9] == 'P';
+                       sig_aload = cell->getPort(ID::E);
                        has_arst = true;
                        pol_arst = type_str[10] == 'P';
                        sig_arst = cell->getPort(ID::R);
                        val_arst = type_str[11] == '1' ? State::S1 : State::S0;
                } else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
                        is_fine = true;
-                       sig_d = cell->getPort(ID::D);
-                       has_en = true;
-                       pol_en = type_str[11] == 'P';
-                       sig_en = cell->getPort(ID::E);
+                       has_aload = true;
+                       sig_ad = cell->getPort(ID::D);
+                       has_aload = true;
+                       pol_aload = type_str[11] == 'P';
+                       sig_aload = cell->getPort(ID::E);
                        has_sr = true;
                        pol_set = type_str[12] == 'P';
                        pol_clr = type_str[13] == 'P';
@@ -264,17 +359,13 @@ struct FfData {
                } else {
                        log_assert(0);
                }
-               if (has_d && sig_d.is_fully_const()) {
-                       d_is_const = true;
-                       val_d = sig_d.as_const();
-                       if (has_en && !has_clk && !has_sr && !has_arst) {
-                               // Plain D latches with const D treated specially.
-                               has_en = has_d = false;
-                               has_arst = true;
-                               sig_arst = sig_en;
-                               pol_arst = pol_en;
-                               val_arst = val_d;
-                       }
+               if (has_aload && !has_clk && !has_sr && !has_arst && sig_ad.is_fully_const()) {
+                       // Plain D latches with const D treated specially.
+                       has_aload = false;
+                       has_arst = true;
+                       sig_arst = sig_aload;
+                       pol_arst = pol_aload;
+                       val_arst = sig_ad.as_const();
                }
        }
 
@@ -282,19 +373,22 @@ struct FfData {
        FfData slice(const std::vector<int> &bits) {
                FfData res(initvals);
                res.sig_clk = sig_clk;
-               res.sig_en = sig_en;
+               res.sig_ce = sig_ce;
+               res.sig_aload = sig_aload;
                res.sig_arst = sig_arst;
                res.sig_srst = sig_srst;
-               res.has_d = has_d;
                res.has_clk = has_clk;
-               res.has_en = has_en;
+               res.has_gclk = has_gclk;
+               res.has_ce = has_ce;
+               res.has_aload = has_aload;
                res.has_arst = has_arst;
                res.has_srst = has_srst;
                res.has_sr = has_sr;
                res.ce_over_srst = ce_over_srst;
                res.is_fine = is_fine;
                res.pol_clk = pol_clk;
-               res.pol_en = pol_en;
+               res.pol_ce = pol_ce;
+               res.pol_aload = pol_aload;
                res.pol_arst = pol_arst;
                res.pol_srst = pol_srst;
                res.pol_clr = pol_clr;
@@ -302,8 +396,10 @@ struct FfData {
                res.attributes = attributes;
                for (int i : bits) {
                        res.sig_q.append(sig_q[i]);
-                       if (has_d)
+                       if (has_clk || has_gclk)
                                res.sig_d.append(sig_d[i]);
+                       if (has_aload)
+                               res.sig_ad.append(sig_ad[i]);
                        if (has_sr) {
                                res.sig_clr.append(sig_clr[i]);
                                res.sig_set.append(sig_set[i]);
@@ -316,39 +412,34 @@ struct FfData {
                                res.val_init.bits.push_back(val_init[i]);
                }
                res.width = GetSize(res.sig_q);
-               // Slicing bits out may cause D to become const.
-               if (has_d && res.sig_d.is_fully_const()) {
-                       res.d_is_const = true;
-                       res.val_d = res.sig_d.as_const();
-               }
                return res;
        }
 
        void unmap_ce(Module *module) {
-               if (!has_en)
+               if (!has_ce)
                        return;
                log_assert(has_clk);
                if (has_srst && ce_over_srst)
                        unmap_srst(module);
 
                if (!is_fine) {
-                       if (pol_en)
-                               sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_en);
+                       if (pol_ce)
+                               sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_ce);
                        else
-                               sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_en);
+                               sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_ce);
                } else {
-                       if (pol_en)
-                               sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_en);
+                       if (pol_ce)
+                               sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_ce);
                        else
-                               sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_en);
+                               sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_ce);
                }
-               has_en = false;
+               has_ce = false;
        }
 
        void unmap_srst(Module *module) {
                if (!has_srst)
                        return;
-               if (has_en && !ce_over_srst)
+               if (has_ce && !ce_over_srst)
                        unmap_ce(module);
 
                if (!is_fine) {
@@ -373,14 +464,14 @@ struct FfData {
        Cell *emit(Module *module, IdString name) {
                if (!width)
                        return nullptr;
-               if (!has_d && !has_sr) {
+               if (!has_aload && !has_clk && !has_gclk && !has_sr) {
                        if (has_arst) {
                                // Convert this case to a D latch.
-                               has_d = has_en = true;
+                               has_aload = true;
                                has_arst = false;
-                               sig_d = val_arst;
-                               sig_en = sig_arst;
-                               pol_en = pol_arst;
+                               sig_ad = val_arst;
+                               sig_aload = sig_arst;
+                               pol_aload = pol_arst;
                        } else {
                                // No control inputs left.  Turn into a const driver.
                                if (initvals)
@@ -393,87 +484,93 @@ struct FfData {
                        initvals->set_init(sig_q, val_init);
                Cell *cell;
                if (!is_fine) {
-                       if (!has_d) {
-                               log_assert(has_sr);
-                               cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
-                       } else if (!has_clk && !has_en) {
+                       if (has_gclk) {
+                               log_assert(!has_clk);
+                               log_assert(!has_ce);
+                               log_assert(!has_aload);
                                log_assert(!has_arst);
                                log_assert(!has_srst);
                                log_assert(!has_sr);
                                cell = module->addFf(name, sig_d, sig_q);
+                       } else if (!has_aload && !has_clk) {
+                               log_assert(has_sr);
+                               cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
                        } else if (!has_clk) {
                                log_assert(!has_srst);
                                if (has_sr)
-                                       cell = module->addDlatchsr(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
+                                       cell = module->addDlatchsr(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
                                else if (has_arst)
-                                       cell = module->addAdlatch(name, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_en, pol_arst);
+                                       cell = module->addAdlatch(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst, pol_aload, pol_arst);
                                else
-                                       cell = module->addDlatch(name, sig_en, sig_d, sig_q, pol_en);
+                                       cell = module->addDlatch(name, sig_aload, sig_ad, sig_q, pol_aload);
                        } else {
                                if (has_sr) {
-                                       if (has_en)
-                                               cell = module->addDffsre(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, pol_set, pol_clr);
+                                       if (has_ce)
+                                               cell = module->addDffsre(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
                                        else
                                                cell = module->addDffsr(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
                                } else if (has_arst) {
-                                       if (has_en)
-                                               cell = module->addAdffe(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_en, pol_arst);
+                                       if (has_ce)
+                                               cell = module->addAdffe(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_ce, pol_arst);
                                        else
                                                cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst);
                                } else if (has_srst) {
-                                       if (has_en)
+                                       if (has_ce)
                                                if (ce_over_srst)
-                                                       cell = module->addSdffce(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
+                                                       cell = module->addSdffce(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
                                                else
-                                                       cell = module->addSdffe(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_en, pol_srst);
+                                                       cell = module->addSdffe(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst);
                                        else
                                                cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst);
                                } else {
-                                       if (has_en)
-                                               cell = module->addDffe(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
+                                       if (has_ce)
+                                               cell = module->addDffe(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
                                        else
                                                cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk);
                                }
                        }
                } else {
-                       if (!has_d) {
-                               log_assert(has_sr);
-                               cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
-                       } else if (!has_clk && !has_en) {
+                       if (has_gclk) {
+                               log_assert(!has_clk);
+                               log_assert(!has_ce);
+                               log_assert(!has_aload);
                                log_assert(!has_arst);
                                log_assert(!has_srst);
                                log_assert(!has_sr);
                                cell = module->addFfGate(name, sig_d, sig_q);
+                       } else if (!has_aload && !has_clk) {
+                               log_assert(has_sr);
+                               cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
                        } else if (!has_clk) {
                                log_assert(!has_srst);
                                if (has_sr)
-                                       cell = module->addDlatchsrGate(name, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_en, pol_set, pol_clr);
+                                       cell = module->addDlatchsrGate(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr);
                                else if (has_arst)
-                                       cell = module->addAdlatchGate(name, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_en, pol_arst);
+                                       cell = module->addAdlatchGate(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst.as_bool(), pol_aload, pol_arst);
                                else
-                                       cell = module->addDlatchGate(name, sig_en, sig_d, sig_q, pol_en);
+                                       cell = module->addDlatchGate(name, sig_aload, sig_ad, sig_q, pol_aload);
                        } else {
                                if (has_sr) {
-                                       if (has_en)
-                                               cell = module->addDffsreGate(name, sig_clk, sig_en, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_en, pol_set, pol_clr);
+                                       if (has_ce)
+                                               cell = module->addDffsreGate(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr);
                                        else
                                                cell = module->addDffsrGate(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr);
                                } else if (has_arst) {
-                                       if (has_en)
-                                               cell = module->addAdffeGate(name, sig_clk, sig_en, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_en, pol_arst);
+                                       if (has_ce)
+                                               cell = module->addAdffeGate(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_ce, pol_arst);
                                        else
                                                cell = module->addAdffGate(name, sig_clk, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_arst);
                                } else if (has_srst) {
-                                       if (has_en)
+                                       if (has_ce)
                                                if (ce_over_srst)
-                                                       cell = module->addSdffceGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, pol_srst);
+                                                       cell = module->addSdffceGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
                                                else
-                                                       cell = module->addSdffeGate(name, sig_clk, sig_en, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_en, pol_srst);
+                                                       cell = module->addSdffeGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst);
                                        else
                                                cell = module->addSdffGate(name, sig_clk, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_srst);
                                } else {
-                                       if (has_en)
-                                               cell = module->addDffeGate(name, sig_clk, sig_en, sig_d, sig_q, pol_clk, pol_en);
+                                       if (has_ce)
+                                               cell = module->addDffeGate(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce);
                                        else
                                                cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk);
                                }
index 6a29acc960c37371b8515044118df2987bb5fdae..7d62a88cfc534f8629a1e24fb3cebf3aa2e250ee 100644 (file)
@@ -62,22 +62,28 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
 
                FfData cur_ff(initvals, cell);
 
-               log_assert(cur_ff.has_d);
+               // Reject latches and $ff.
+               if (!cur_ff.has_clk)
+                       return false;
+
                log_assert((*sigmap)(cur_ff.sig_d[idx]) == bit);
 
                if (!found) {
                        ff.sig_clk = cur_ff.sig_clk;
-                       ff.sig_en = cur_ff.sig_en;
+                       ff.sig_ce = cur_ff.sig_ce;
+                       ff.sig_aload = cur_ff.sig_aload;
                        ff.sig_srst = cur_ff.sig_srst;
                        ff.sig_arst = cur_ff.sig_arst;
                        ff.has_clk = cur_ff.has_clk;
-                       ff.has_en = cur_ff.has_en;
+                       ff.has_ce = cur_ff.has_ce;
+                       ff.has_aload = cur_ff.has_aload;
                        ff.has_srst = cur_ff.has_srst;
                        ff.has_arst = cur_ff.has_arst;
                        ff.has_sr = cur_ff.has_sr;
                        ff.ce_over_srst = cur_ff.ce_over_srst;
                        ff.pol_clk = cur_ff.pol_clk;
-                       ff.pol_en = cur_ff.pol_en;
+                       ff.pol_ce = cur_ff.pol_ce;
+                       ff.pol_aload = cur_ff.pol_aload;
                        ff.pol_arst = cur_ff.pol_arst;
                        ff.pol_srst = cur_ff.pol_srst;
                        ff.pol_clr = cur_ff.pol_clr;
@@ -85,7 +91,9 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
                } else {
                        if (ff.has_clk != cur_ff.has_clk)
                                return false;
-                       if (ff.has_en != cur_ff.has_en)
+                       if (ff.has_ce != cur_ff.has_ce)
+                               return false;
+                       if (ff.has_aload != cur_ff.has_aload)
                                return false;
                        if (ff.has_srst != cur_ff.has_srst)
                                return false;
@@ -99,10 +107,16 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
                                if (ff.pol_clk != cur_ff.pol_clk)
                                        return false;
                        }
-                       if (ff.has_en) {
-                               if (ff.sig_en != cur_ff.sig_en)
+                       if (ff.has_ce) {
+                               if (ff.sig_ce != cur_ff.sig_ce)
+                                       return false;
+                               if (ff.pol_ce != cur_ff.pol_ce)
+                                       return false;
+                       }
+                       if (ff.has_aload) {
+                               if (ff.sig_aload != cur_ff.sig_aload)
                                        return false;
-                               if (ff.pol_en != cur_ff.pol_en)
+                               if (ff.pol_aload != cur_ff.pol_aload)
                                        return false;
                        }
                        if (ff.has_srst) {
@@ -110,7 +124,7 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
                                        return false;
                                if (ff.pol_srst != cur_ff.pol_srst)
                                        return false;
-                               if (ff.has_en && ff.ce_over_srst != cur_ff.ce_over_srst)
+                               if (ff.has_ce && ff.ce_over_srst != cur_ff.ce_over_srst)
                                        return false;
                        }
                        if (ff.has_arst) {
@@ -129,6 +143,7 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pai
 
                ff.width++;
                ff.sig_d.append(cur_ff.sig_d[idx]);
+               ff.sig_ad.append(ff.has_aload ? cur_ff.sig_ad[idx] : State::Sx);
                ff.sig_q.append(cur_ff.sig_q[idx]);
                ff.sig_clr.append(ff.has_sr ? cur_ff.sig_clr[idx] : State::S0);
                ff.sig_set.append(ff.has_sr ? cur_ff.sig_set[idx] : State::S0);
@@ -179,28 +194,33 @@ bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair
 
                if (!found) {
                        ff.sig_clk = cur_ff.sig_clk;
-                       ff.sig_en = cur_ff.sig_en;
+                       ff.sig_ce = cur_ff.sig_ce;
+                       ff.sig_aload = cur_ff.sig_aload;
                        ff.sig_srst = cur_ff.sig_srst;
                        ff.sig_arst = cur_ff.sig_arst;
-                       ff.has_d = cur_ff.has_d;
                        ff.has_clk = cur_ff.has_clk;
-                       ff.has_en = cur_ff.has_en;
+                       ff.has_gclk = cur_ff.has_gclk;
+                       ff.has_ce = cur_ff.has_ce;
+                       ff.has_aload = cur_ff.has_aload;
                        ff.has_srst = cur_ff.has_srst;
                        ff.has_arst = cur_ff.has_arst;
                        ff.has_sr = cur_ff.has_sr;
                        ff.ce_over_srst = cur_ff.ce_over_srst;
                        ff.pol_clk = cur_ff.pol_clk;
-                       ff.pol_en = cur_ff.pol_en;
+                       ff.pol_ce = cur_ff.pol_ce;
+                       ff.pol_aload = cur_ff.pol_aload;
                        ff.pol_arst = cur_ff.pol_arst;
                        ff.pol_srst = cur_ff.pol_srst;
                        ff.pol_clr = cur_ff.pol_clr;
                        ff.pol_set = cur_ff.pol_set;
                } else {
-                       if (ff.has_d != cur_ff.has_d)
+                       if (ff.has_gclk != cur_ff.has_gclk)
                                return false;
                        if (ff.has_clk != cur_ff.has_clk)
                                return false;
-                       if (ff.has_en != cur_ff.has_en)
+                       if (ff.has_ce != cur_ff.has_ce)
+                               return false;
+                       if (ff.has_aload != cur_ff.has_aload)
                                return false;
                        if (ff.has_srst != cur_ff.has_srst)
                                return false;
@@ -214,10 +234,16 @@ bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair
                                if (ff.pol_clk != cur_ff.pol_clk)
                                        return false;
                        }
-                       if (ff.has_en) {
-                               if (ff.sig_en != cur_ff.sig_en)
+                       if (ff.has_ce) {
+                               if (ff.sig_ce != cur_ff.sig_ce)
+                                       return false;
+                               if (ff.pol_ce != cur_ff.pol_ce)
+                                       return false;
+                       }
+                       if (ff.has_aload) {
+                               if (ff.sig_aload != cur_ff.sig_aload)
                                        return false;
-                               if (ff.pol_en != cur_ff.pol_en)
+                               if (ff.pol_aload != cur_ff.pol_aload)
                                        return false;
                        }
                        if (ff.has_srst) {
@@ -225,7 +251,7 @@ bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair
                                        return false;
                                if (ff.pol_srst != cur_ff.pol_srst)
                                        return false;
-                               if (ff.has_en && ff.ce_over_srst != cur_ff.ce_over_srst)
+                               if (ff.has_ce && ff.ce_over_srst != cur_ff.ce_over_srst)
                                        return false;
                        }
                        if (ff.has_arst) {
@@ -243,7 +269,8 @@ bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair
                }
 
                ff.width++;
-               ff.sig_d.append(ff.has_d ? cur_ff.sig_d[idx] : State::Sx);
+               ff.sig_d.append((ff.has_clk || ff.has_gclk) ? cur_ff.sig_d[idx] : State::Sx);
+               ff.sig_ad.append(ff.has_aload ? cur_ff.sig_ad[idx] : State::Sx);
                ff.sig_q.append(cur_ff.sig_q[idx]);
                ff.sig_clr.append(ff.has_sr ? cur_ff.sig_clr[idx] : State::S0);
                ff.sig_set.append(ff.has_sr ? cur_ff.sig_set[idx] : State::S0);
index b176e40575c0ca28540abc43dfc4b74c822865d1..40659b15b1bc64b6e52f0f6abacefba3890a063b 100644 (file)
@@ -961,9 +961,9 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
                ff.sig_clk = port.clk;
                ff.pol_clk = port.clk_polarity;
                if (port.en != State::S1) {
-                       ff.has_en = true;
-                       ff.pol_en = true;
-                       ff.sig_en = port.en;
+                       ff.has_ce = true;
+                       ff.pol_ce = true;
+                       ff.sig_ce = port.en;
                }
                if (port.arst != State::S0) {
                        ff.has_arst = true;
@@ -976,7 +976,7 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
                        ff.pol_srst = true;
                        ff.sig_srst = port.srst;
                        ff.val_srst = port.srst_value;
-                       ff.ce_over_srst = ff.has_en && port.ce_over_srst;
+                       ff.ce_over_srst = ff.has_ce && port.ce_over_srst;
                }
                ff.sig_d = sig_d;
                ff.sig_q = port.data;
@@ -1163,15 +1163,14 @@ void Mem::emulate_transparency(int widx, int ridx, FfInitVals *initvals) {
                        FfData ff(initvals);
                        ff.width = 1;
                        ff.sig_q = cond_q;
-                       ff.has_d = true;
                        ff.sig_d = cond;
                        ff.has_clk = true;
                        ff.sig_clk = rport.clk;
                        ff.pol_clk = rport.clk_polarity;
                        if (rport.en != State::S1) {
-                               ff.has_en = true;
-                               ff.sig_en = rport.en;
-                               ff.pol_en = true;
+                               ff.has_ce = true;
+                               ff.sig_ce = rport.en;
+                               ff.pol_ce = true;
                        }
                        if (rport.arst != State::S0) {
                                ff.has_arst = true;
index 7ad56c1179cb7aca359b178c11cafe4d8a3fa1a5..214826f5ab58be12dcf2e34e3199a8c1dba711e2 100644 (file)
@@ -1081,7 +1081,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
                FfData ff(nullptr, cell);
 
                // Latches and FFs with async inputs are not supported — use clk2fflogic or async2sync first.
-               if (!ff.has_d || ff.has_arst || ff.has_sr || (ff.has_en && !ff.has_clk))
+               if (ff.has_aload || ff.has_arst || ff.has_sr)
                        return false;
 
                if (timestep == 1)
@@ -1094,7 +1094,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
                        std::vector<int> undef_d;
                        if (model_undef)
                                undef_d = importUndefSigSpec(cell->getPort(ID::D), timestep-1);
-                       if (ff.has_srst && ff.has_en && ff.ce_over_srst) {
+                       if (ff.has_srst && ff.has_ce && ff.ce_over_srst) {
                                int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0);
                                std::vector<int> rval = importDefSigSpec(ff.val_srst, timestep-1);
                                int undef_srst;
@@ -1108,21 +1108,21 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
                                else
                                        std::tie(d, undef_d) = mux(srst, undef_srst, rval, undef_rval, d, undef_d);
                        }
-                       if (ff.has_en) {
-                               int en = importDefSigSpec(ff.sig_en, timestep-1).at(0);
+                       if (ff.has_ce) {
+                               int ce = importDefSigSpec(ff.sig_ce, timestep-1).at(0);
                                std::vector<int> old_q = importDefSigSpec(ff.sig_q, timestep-1);
-                               int undef_en;
+                               int undef_ce;
                                std::vector<int> undef_old_q;
                                if (model_undef) {
-                                       undef_en = importUndefSigSpec(ff.sig_en, timestep-1).at(0);
+                                       undef_ce = importUndefSigSpec(ff.sig_ce, timestep-1).at(0);
                                        undef_old_q = importUndefSigSpec(ff.sig_q, timestep-1);
                                }
-                               if (ff.pol_en)
-                                       std::tie(d, undef_d) = mux(en, undef_en, old_q, undef_old_q, d, undef_d);
+                               if (ff.pol_ce)
+                                       std::tie(d, undef_d) = mux(ce, undef_ce, old_q, undef_old_q, d, undef_d);
                                else
-                                       std::tie(d, undef_d) = mux(en, undef_en, d, undef_d, old_q, undef_old_q);
+                                       std::tie(d, undef_d) = mux(ce, undef_ce, d, undef_d, old_q, undef_old_q);
                        }
-                       if (ff.has_srst && !(ff.has_en && ff.ce_over_srst)) {
+                       if (ff.has_srst && !(ff.has_ce && ff.ce_over_srst)) {
                                int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0);
                                std::vector<int> rval = importDefSigSpec(ff.val_srst, timestep-1);
                                int undef_srst;
index 21962c238c92b1d15a3e56cda5c1dc9ac2a10805..b87ecdd9987224854028c4d6ad3f47aeb1918edc 100644 (file)
@@ -71,9 +71,9 @@ struct MemQueryCache
                // port_ren is an upper bound on when we care about the value fetched
                // from memory this cycle.
                int ren = ezSAT::CONST_TRUE;
-               if (ff.has_en) {
-                       ren = qcsat.importSigBit(ff.sig_en);
-                       if (!ff.pol_en)
+               if (ff.has_ce) {
+                       ren = qcsat.importSigBit(ff.sig_ce);
+                       if (!ff.pol_ce)
                                ren = qcsat.ez->NOT(ren);
                }
                if (ff.has_srst) {
@@ -347,6 +347,10 @@ struct MemoryDffWorker
                        log("output latches are not supported.\n");
                        return;
                }
+               if (ff.has_aload) {
+                       log("output FF has async load, not supported.\n");
+                       return;
+               }
                if (ff.has_sr) {
                        // Latches and FFs with SR are not supported.
                        log("output FF has both set and reset, not supported.\n");
@@ -491,8 +495,8 @@ struct MemoryDffWorker
                log("merging output FF to cell.\n");
 
                merger.remove_output_ff(bits);
-               if (ff.has_en && !ff.pol_en)
-                       ff.sig_en = module->LogicNot(NEW_ID, ff.sig_en);
+               if (ff.has_ce && !ff.pol_ce)
+                       ff.sig_ce = module->LogicNot(NEW_ID, ff.sig_ce);
                if (ff.has_arst && !ff.pol_arst)
                        ff.sig_arst = module->LogicNot(NEW_ID, ff.sig_arst);
                if (ff.has_srst && !ff.pol_srst)
@@ -500,8 +504,8 @@ struct MemoryDffWorker
                port.clk = ff.sig_clk;
                port.clk_enable = true;
                port.clk_polarity = ff.pol_clk;
-               if (ff.has_en)
-                       port.en = ff.sig_en;
+               if (ff.has_ce)
+                       port.en = ff.sig_ce;
                else
                        port.en = State::S1;
                if (ff.has_arst) {
@@ -551,6 +555,10 @@ struct MemoryDffWorker
                        log("address latches are not supported.\n");
                        return;
                }
+               if (ff.has_aload) {
+                       log("address FF has async load, not supported.\n");
+                       return;
+               }
                if (ff.has_sr || ff.has_arst) {
                        log("address FF has async set and/or reset, not supported.\n");
                        return;
index ddf08392bb83619145849601f1dd0cce3510ddfa..0e25484b8d3267b5881219f0f3abca9355bdb3d1 100644 (file)
@@ -382,6 +382,69 @@ struct OptDffWorker
                                }
                        }
 
+                       if (ff.has_aload) {
+                               if (ff.sig_aload == (ff.pol_aload ? State::S0 : State::S1) || (!opt.keepdc && ff.sig_aload == State::Sx)) {
+                                       // Always-inactive enable — remove.
+                                       log("Removing never-active async load on %s (%s) from module %s.\n",
+                                                       log_id(cell), log_id(cell->type), log_id(module));
+                                       ff.has_aload = false;
+                                       changed = true;
+                               } else if (ff.sig_aload == (ff.pol_aload ? State::S1 : State::S0)) {
+                                       // Always-active enable.  Make a comb circuit, nuke the FF/latch.
+                                       log("Handling always-active async load on %s (%s) from module %s (changing to combinatorial circuit).\n",
+                                                       log_id(cell), log_id(cell->type), log_id(module));
+                                       initvals.remove_init(ff.sig_q);
+                                       module->remove(cell);
+                                       if (ff.has_sr) {
+                                               SigSpec tmp;
+                                               if (ff.is_fine) {
+                                                       if (ff.pol_set)
+                                                               tmp = module->MuxGate(NEW_ID, ff.sig_ad, State::S1, ff.sig_set);
+                                                       else
+                                                               tmp = module->MuxGate(NEW_ID, State::S1, ff.sig_ad, ff.sig_set);
+                                                       if (ff.pol_clr)
+                                                               module->addMuxGate(NEW_ID, tmp, State::S0, ff.sig_clr, ff.sig_q);
+                                                       else
+                                                               module->addMuxGate(NEW_ID, State::S0, tmp, ff.sig_clr, ff.sig_q);
+                                               } else {
+                                                       if (ff.pol_set)
+                                                               tmp = module->Or(NEW_ID, ff.sig_ad, ff.sig_set);
+                                                       else
+                                                               tmp = module->Or(NEW_ID, ff.sig_ad, module->Not(NEW_ID, ff.sig_set));
+                                                       if (ff.pol_clr)
+                                                               module->addAnd(NEW_ID, tmp, module->Not(NEW_ID, ff.sig_clr), ff.sig_q);
+                                                       else
+                                                               module->addAnd(NEW_ID, tmp, ff.sig_clr, ff.sig_q);
+                                               }
+                                       } else if (ff.has_arst) {
+                                               if (ff.is_fine) {
+                                                       if (ff.pol_arst)
+                                                               module->addMuxGate(NEW_ID, ff.sig_ad, ff.val_arst[0], ff.sig_arst, ff.sig_q);
+                                                       else
+                                                               module->addMuxGate(NEW_ID, ff.val_arst[0], ff.sig_ad, ff.sig_arst, ff.sig_q);
+                                               } else {
+                                                       if (ff.pol_arst)
+                                                               module->addMux(NEW_ID, ff.sig_ad, ff.val_arst, ff.sig_arst, ff.sig_q);
+                                                       else
+                                                               module->addMux(NEW_ID, ff.val_arst, ff.sig_ad, ff.sig_arst, ff.sig_q);
+                                               }
+                                       } else {
+                                               module->connect(ff.sig_q, ff.sig_ad);
+                                       }
+                                       did_something = true;
+                                       continue;
+                               } else if (ff.sig_ad.is_fully_const() && !ff.has_arst && !ff.has_sr) {
+                                       log("Changing const-value async load to async reset on %s (%s) from module %s.\n",
+                                                       log_id(cell), log_id(cell->type), log_id(module));
+                                       ff.has_arst = true;
+                                       ff.has_aload = false;
+                                       ff.sig_arst = ff.sig_aload;
+                                       ff.pol_arst = ff.pol_aload;
+                                       ff.val_arst = ff.sig_ad.as_const();
+                                       changed = true;
+                               }
+                       }
+
                        if (ff.has_arst) {
                                if (ff.sig_arst == (ff.pol_arst ? State::S0 : State::S1)) {
                                        // Always-inactive reset — remove.
@@ -414,111 +477,63 @@ struct OptDffWorker
                                                        log_id(cell), log_id(cell->type), log_id(module));
                                        ff.has_srst = false;
                                        if (!ff.ce_over_srst)
-                                               ff.has_en = false;
-                                       ff.sig_d = ff.val_d = ff.val_srst;
-                                       ff.d_is_const = true;
+                                               ff.has_ce = false;
+                                       ff.sig_d = ff.val_srst;
                                        changed = true;
                                }
                        }
 
-                       if (ff.has_en) {
-                               if (ff.sig_en == (ff.pol_en ? State::S0 : State::S1) || (!opt.keepdc && ff.sig_en == State::Sx)) {
+                       if (ff.has_ce) {
+                               if (ff.sig_ce == (ff.pol_ce ? State::S0 : State::S1) || (!opt.keepdc && ff.sig_ce == State::Sx)) {
                                        // Always-inactive enable — remove.
-                                       if (ff.has_clk && ff.has_srst && !ff.ce_over_srst) {
+                                       if (ff.has_srst && !ff.ce_over_srst) {
                                                log("Handling never-active EN on %s (%s) from module %s (connecting SRST instead).\n",
                                                                log_id(cell), log_id(cell->type), log_id(module));
                                                // FF with sync reset — connect the sync reset to D instead.
-                                               ff.pol_en = ff.pol_srst;
-                                               ff.sig_en = ff.sig_srst;
+                                               ff.pol_ce = ff.pol_srst;
+                                               ff.sig_ce = ff.sig_srst;
                                                ff.has_srst = false;
-                                               ff.sig_d = ff.val_d = ff.val_srst;
-                                               ff.d_is_const = true;
+                                               ff.sig_d = ff.val_srst;
                                                changed = true;
                                        } else {
                                                log("Handling never-active EN on %s (%s) from module %s (removing D path).\n",
                                                                log_id(cell), log_id(cell->type), log_id(module));
-                                               // The D input path is effectively useless, so remove it (this will be a const-input D latch, SR latch, or a const driver).
-                                               ff.has_d = ff.has_en = ff.has_clk = false;
+                                               // The D input path is effectively useless, so remove it (this will be a D latch, SR latch, or a const driver).
+                                               ff.has_ce = ff.has_clk = ff.has_srst = false;
                                                changed = true;
                                        }
-                               } else if (ff.sig_en == (ff.pol_en ? State::S1 : State::S0)) {
-                                       // Always-active enable.
-                                       if (ff.has_clk) {
-                                               // For FF, just remove the useless enable.
-                                               log("Removing always-active EN on %s (%s) from module %s.\n",
-                                                               log_id(cell), log_id(cell->type), log_id(module));
-                                               ff.has_en = false;
-                                               changed = true;
-                                       } else {
-                                               // For latches, make a comb circuit, nuke the latch.
-                                               log("Handling always-active EN on %s (%s) from module %s (changing to combinatorial circuit).\n",
-                                                               log_id(cell), log_id(cell->type), log_id(module));
-                                               initvals.remove_init(ff.sig_q);
-                                               module->remove(cell);
-                                               if (ff.has_sr) {
-                                                       SigSpec tmp;
-                                                       if (ff.is_fine) {
-                                                               if (ff.pol_set)
-                                                                       tmp = module->MuxGate(NEW_ID, ff.sig_d, State::S1, ff.sig_set);
-                                                               else
-                                                                       tmp = module->MuxGate(NEW_ID, State::S1, ff.sig_d, ff.sig_set);
-                                                               if (ff.pol_clr)
-                                                                       module->addMuxGate(NEW_ID, tmp, State::S0, ff.sig_clr, ff.sig_q);
-                                                               else
-                                                                       module->addMuxGate(NEW_ID, State::S0, tmp, ff.sig_clr, ff.sig_q);
-                                                       } else {
-                                                               if (ff.pol_set)
-                                                                       tmp = module->Or(NEW_ID, ff.sig_d, ff.sig_set);
-                                                               else
-                                                                       tmp = module->Or(NEW_ID, ff.sig_d, module->Not(NEW_ID, ff.sig_set));
-                                                               if (ff.pol_clr)
-                                                                       module->addAnd(NEW_ID, tmp, module->Not(NEW_ID, ff.sig_clr), ff.sig_q);
-                                                               else
-                                                                       module->addAnd(NEW_ID, tmp, ff.sig_clr, ff.sig_q);
-                                                       }
-                                               } else if (ff.has_arst) {
-                                                       if (ff.is_fine) {
-                                                               if (ff.pol_arst)
-                                                                       module->addMuxGate(NEW_ID, ff.sig_d, ff.val_arst[0], ff.sig_arst, ff.sig_q);
-                                                               else
-                                                                       module->addMuxGate(NEW_ID, ff.val_arst[0], ff.sig_d, ff.sig_arst, ff.sig_q);
-                                                       } else {
-                                                               if (ff.pol_arst)
-                                                                       module->addMux(NEW_ID, ff.sig_d, ff.val_arst, ff.sig_arst, ff.sig_q);
-                                                               else
-                                                                       module->addMux(NEW_ID, ff.val_arst, ff.sig_d, ff.sig_arst, ff.sig_q);
-                                                       }
-                                               } else {
-                                                       module->connect(ff.sig_q, ff.sig_d);
-                                               }
-                                               did_something = true;
-                                               continue;
-                                       }
+                               } else if (ff.sig_ce == (ff.pol_ce ? State::S1 : State::S0)) {
+                                       // Always-active enable.  Just remove it.
+                                       // For FF, just remove the useless enable.
+                                       log("Removing always-active EN on %s (%s) from module %s.\n",
+                                                       log_id(cell), log_id(cell->type), log_id(module));
+                                       ff.has_ce = false;
+                                       changed = true;
                                }
                        }
 
                        if (ff.has_clk) {
                                if (ff.sig_clk.is_fully_const()) {
-                                       // Const clock — the D input path is effectively useless, so remove it (this will be a const-input D latch, SR latch, or a const driver).
+                                       // Const clock — the D input path is effectively useless, so remove it (this will be a D latch, SR latch, or a const driver).
                                        log("Handling const CLK on %s (%s) from module %s (removing D path).\n",
                                                        log_id(cell), log_id(cell->type), log_id(module));
-                                       ff.has_d = ff.has_en = ff.has_clk = ff.has_srst = false;
+                                       ff.has_ce = ff.has_clk = ff.has_srst = false;
                                        changed = true;
                                }
                        }
 
-                       if (ff.has_d && ff.sig_d == ff.sig_q) {
+                       if ((ff.has_clk || ff.has_gclk) && ff.sig_d == ff.sig_q) {
                                // Q wrapped back to D, can be removed.
                                if (ff.has_clk && ff.has_srst) {
                                        // FF with sync reset — connect the sync reset to D instead.
                                        log("Handling D = Q on %s (%s) from module %s (conecting SRST instead).\n",
                                                        log_id(cell), log_id(cell->type), log_id(module));
-                                       if (ff.has_en && ff.ce_over_srst) {
-                                               if (!ff.pol_en) {
+                                       if (ff.has_ce && ff.ce_over_srst) {
+                                               if (!ff.pol_ce) {
                                                        if (ff.is_fine)
-                                                               ff.sig_en = module->NotGate(NEW_ID, ff.sig_en);
+                                                               ff.sig_ce = module->NotGate(NEW_ID, ff.sig_ce);
                                                        else
-                                                               ff.sig_en = module->Not(NEW_ID, ff.sig_en);
+                                                               ff.sig_ce = module->Not(NEW_ID, ff.sig_ce);
                                                }
                                                if (!ff.pol_srst) {
                                                        if (ff.is_fine)
@@ -527,28 +542,34 @@ struct OptDffWorker
                                                                ff.sig_srst = module->Not(NEW_ID, ff.sig_srst);
                                                }
                                                if (ff.is_fine)
-                                                       ff.sig_en = module->AndGate(NEW_ID, ff.sig_en, ff.sig_srst);
+                                                       ff.sig_ce = module->AndGate(NEW_ID, ff.sig_ce, ff.sig_srst);
                                                else
-                                                       ff.sig_en = module->And(NEW_ID, ff.sig_en, ff.sig_srst);
-                                               ff.pol_en = true;
+                                                       ff.sig_ce = module->And(NEW_ID, ff.sig_ce, ff.sig_srst);
+                                               ff.pol_ce = true;
                                        } else {
-                                               ff.pol_en = ff.pol_srst;
-                                               ff.sig_en = ff.sig_srst;
+                                               ff.pol_ce = ff.pol_srst;
+                                               ff.sig_ce = ff.sig_srst;
                                        }
-                                       ff.has_en = true;
+                                       ff.has_ce = true;
                                        ff.has_srst = false;
-                                       ff.sig_d = ff.val_d = ff.val_srst;
-                                       ff.d_is_const = true;
+                                       ff.sig_d = ff.val_srst;
                                        changed = true;
                                } else {
                                        // The D input path is effectively useless, so remove it (this will be a const-input D latch, SR latch, or a const driver).
                                        log("Handling D = Q on %s (%s) from module %s (removing D path).\n",
                                                        log_id(cell), log_id(cell->type), log_id(module));
-                                       ff.has_d = ff.has_en = ff.has_clk = false;
+                                       ff.has_clk = ff.has_ce = ff.has_clk = false;
                                        changed = true;
                                }
                        }
 
+                       if (ff.has_aload && !ff.has_clk && ff.sig_ad == ff.sig_q) {
+                               log("Handling AD = Q on %s (%s) from module %s (removing async load path).\n",
+                                               log_id(cell), log_id(cell->type), log_id(module));
+                               ff.has_aload = false;
+                               changed = true;
+                       }
+
                        // Now check if any bit can be replaced by a constant.
                        pool<int> removed_sigbits;
                        for (int i = 0; i < ff.width; i++) {
@@ -565,7 +586,7 @@ struct OptDffWorker
                                }
                                if (val == State::Sm)
                                        continue;
-                               if (ff.has_d) {
+                               if (ff.has_clk || ff.has_gclk) {
                                        if (!ff.sig_d[i].wire) {
                                                val = combine_const(val, ff.sig_d[i].data);
                                                if (val == State::Sm)
@@ -593,6 +614,34 @@ struct OptDffWorker
                                                        continue;
                                        }
                                }
+                               if (ff.has_aload) {
+                                       if (!ff.sig_ad[i].wire) {
+                                               val = combine_const(val, ff.sig_ad[i].data);
+                                               if (val == State::Sm)
+                                                       continue;
+                                       } else {
+                                               if (!opt.sat)
+                                                       continue;
+                                               // For each register bit, try to prove that it cannot change from the initial value. If so, remove it
+                                               if (!modwalker.has_drivers(ff.sig_ad.extract(i)))
+                                                       continue;
+                                               if (val != State::S0 && val != State::S1)
+                                                       continue;
+
+                                               int init_sat_pi = qcsat.importSigBit(val);
+                                               int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]);
+                                               int d_sat_pi = qcsat.importSigBit(ff.sig_ad[i]);
+
+                                               qcsat.prepare();
+
+                                               // Try to find out whether the register bit can change under some circumstances
+                                               bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.ez->IFF(d_sat_pi, init_sat_pi)));
+
+                                               // If the register bit cannot change, we can replace it with a constant
+                                               if (counter_example_found)
+                                                       continue;
+                                       }
+                               }
                                log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", val ? 1 : 0,
                                                i, log_id(cell), log_id(cell->type), log_id(module));
 
@@ -616,7 +665,7 @@ struct OptDffWorker
 
                        // The cell has been simplified as much as possible already.  Now try to spice it up with enables / sync resets.
                        if (ff.has_clk) {
-                               if (!ff.has_arst && !ff.has_sr && (!ff.has_srst || !ff.has_en || ff.ce_over_srst) && !opt.nosdff) {
+                               if (!ff.has_arst && !ff.has_sr && (!ff.has_srst || !ff.has_ce || ff.ce_over_srst) && !opt.nosdff) {
                                        // Try to merge sync resets.
                                        std::map<ctrls_t, std::vector<int>> groups;
                                        std::vector<int> remaining_indices;
@@ -677,7 +726,7 @@ struct OptDffWorker
                                                new_ff.has_srst = true;
                                                new_ff.sig_srst = srst.first;
                                                new_ff.pol_srst = srst.second;
-                                               if (new_ff.has_en)
+                                               if (new_ff.has_ce)
                                                        new_ff.ce_over_srst = true;
                                                Cell *new_cell = new_ff.emit(module, NEW_ID);
                                                if (new_cell)
@@ -695,7 +744,7 @@ struct OptDffWorker
                                                changed = true;
                                        }
                                }
-                               if ((!ff.has_srst || !ff.has_en || !ff.ce_over_srst) && !opt.nodffe) {
+                               if ((!ff.has_srst || !ff.has_ce || !ff.ce_over_srst) && !opt.nodffe) {
                                        // Try to merge enables.
                                        std::map<std::pair<patterns_t, ctrls_t>, std::vector<int>> groups;
                                        std::vector<int> remaining_indices;
@@ -725,8 +774,8 @@ struct OptDffWorker
                                                if (!opt.simple_dffe)
                                                        patterns = find_muxtree_feedback_patterns(ff.sig_d[i], ff.sig_q[i], pattern_t());
                                                if (!patterns.empty() || !enables.empty()) {
-                                                       if (ff.has_en)
-                                                               enables.insert(ctrl_t(ff.sig_en, ff.pol_en));
+                                                       if (ff.has_ce)
+                                                               enables.insert(ctrl_t(ff.sig_ce, ff.pol_ce));
                                                        simplify_patterns(patterns);
                                                        groups[std::make_pair(patterns, enables)].push_back(i);
                                                } else
@@ -737,9 +786,9 @@ struct OptDffWorker
                                                FfData new_ff = ff.slice(it.second);
                                                ctrl_t en = make_patterns_logic(it.first.first, it.first.second, ff.is_fine);
 
-                                               new_ff.has_en = true;
-                                               new_ff.sig_en = en.first;
-                                               new_ff.pol_en = en.second;
+                                               new_ff.has_ce = true;
+                                               new_ff.sig_ce = en.first;
+                                               new_ff.pol_ce = en.second;
                                                new_ff.ce_over_srst = false;
                                                Cell *new_cell = new_ff.emit(module, NEW_ID);
                                                if (new_cell)
index a2b51677e06f47da98829151be13d0373dc34b81..f1b93d084727f1c3e15ff9980654893e7a38be48 100644 (file)
@@ -41,8 +41,6 @@ struct Async2syncPass : public Pass {
                log("reset value in the next cycle regardless of the data-in value at the time of\n");
                log("the clock edge.\n");
                log("\n");
-               log("Currently only $adff, $dffsr, and $dlatch cells are supported by this pass.\n");
-               log("\n");
        }
        void execute(std::vector<std::string> args, RTLIL::Design *design) override
        {
@@ -74,14 +72,11 @@ struct Async2syncPass : public Pass {
                                FfData ff(&initvals, cell);
 
                                // Skip for $_FF_ and $ff cells.
-                               if (ff.has_d && !ff.has_clk && !ff.has_en)
+                               if (ff.has_gclk)
                                        continue;
 
                                if (ff.has_clk)
                                {
-                                       if (!ff.has_sr && !ff.has_arst)
-                                               continue;
-
                                        if (ff.has_sr) {
                                                ff.unmap_ce_srst(module);
 
@@ -128,6 +123,39 @@ struct Async2syncPass : public Pass {
                                                ff.sig_d = new_d;
                                                ff.sig_q = new_q;
                                                ff.has_sr = false;
+                                       } else if (ff.has_aload) {
+                                               ff.unmap_ce_srst(module);
+
+                                               log("Replacing %s.%s (%s): ALOAD=%s, AD=%s, D=%s, Q=%s\n",
+                                                               log_id(module), log_id(cell), log_id(cell->type),
+                                                               log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_d), log_signal(ff.sig_q));
+
+                                               initvals.remove_init(ff.sig_q);
+
+                                               Wire *new_d = module->addWire(NEW_ID, ff.width);
+                                               Wire *new_q = module->addWire(NEW_ID, ff.width);
+
+                                               if (ff.pol_aload) {
+                                                       if (!ff.is_fine) {
+                                                               module->addMux(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, ff.sig_q);
+                                                               module->addMux(NEW_ID, ff.sig_d, ff.sig_ad, ff.sig_aload, new_d);
+                                                       } else {
+                                                               module->addMuxGate(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, ff.sig_q);
+                                                               module->addMuxGate(NEW_ID, ff.sig_d, ff.sig_ad, ff.sig_aload, new_d);
+                                                       }
+                                               } else {
+                                                       if (!ff.is_fine) {
+                                                               module->addMux(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, ff.sig_q);
+                                                               module->addMux(NEW_ID, ff.sig_ad, ff.sig_d, ff.sig_aload, new_d);
+                                                       } else {
+                                                               module->addMuxGate(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, ff.sig_q);
+                                                               module->addMuxGate(NEW_ID, ff.sig_ad, ff.sig_d, ff.sig_aload, new_d);
+                                                       }
+                                               }
+
+                                               ff.sig_d = new_d;
+                                               ff.sig_q = new_q;
+                                               ff.has_aload = false;
                                        } else if (ff.has_arst) {
                                                ff.unmap_srst(module);
 
@@ -154,9 +182,12 @@ struct Async2syncPass : public Pass {
                                                ff.sig_q = new_q;
                                                ff.has_arst = false;
                                                ff.has_srst = true;
+                                               ff.ce_over_srst = false;
                                                ff.val_srst = ff.val_arst;
                                                ff.sig_srst = ff.sig_arst;
                                                ff.pol_srst = ff.pol_arst;
+                                       } else {
+                                               continue;
                                        }
                                }
                                else
@@ -164,25 +195,25 @@ struct Async2syncPass : public Pass {
                                        // Latch.
                                        log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
                                                        log_id(module), log_id(cell), log_id(cell->type),
-                                                       log_signal(ff.sig_en), log_signal(ff.sig_d), log_signal(ff.sig_q));
+                                                       log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_q));
 
                                        initvals.remove_init(ff.sig_q);
 
                                        Wire *new_q = module->addWire(NEW_ID, ff.width);
                                        Wire *new_d;
 
-                                       if (ff.has_d) {
+                                       if (ff.has_aload) {
                                                new_d = module->addWire(NEW_ID, ff.width);
-                                               if (ff.pol_en) {
+                                               if (ff.pol_aload) {
                                                        if (!ff.is_fine)
-                                                               module->addMux(NEW_ID, new_q, ff.sig_d, ff.sig_en, new_d);
+                                                               module->addMux(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, new_d);
                                                        else
-                                                               module->addMuxGate(NEW_ID, new_q, ff.sig_d, ff.sig_en, new_d);
+                                                               module->addMuxGate(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, new_d);
                                                } else {
                                                        if (!ff.is_fine)
-                                                               module->addMux(NEW_ID, ff.sig_d, new_q, ff.sig_en, new_d);
+                                                               module->addMux(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, new_d);
                                                        else
-                                                               module->addMuxGate(NEW_ID, ff.sig_d, new_q, ff.sig_en, new_d);
+                                                               module->addMuxGate(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, new_d);
                                                }
                                        } else {
                                                new_d = new_q;
@@ -231,10 +262,10 @@ struct Async2syncPass : public Pass {
 
                                        ff.sig_d = new_d;
                                        ff.sig_q = new_q;
-                                       ff.has_en = false;
+                                       ff.has_aload = false;
                                        ff.has_arst = false;
                                        ff.has_sr = false;
-                                       ff.has_d = true;
+                                       ff.has_gclk = true;
                                }
 
                                IdString name = cell->name;
index 06208397216c3f30c3b8f9297a129dfae22af083..d90206b465aaa325c85b12f9fd0590f6d248200d 100644 (file)
@@ -148,7 +148,7 @@ struct Clk2fflogicPass : public Pass {
                                if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
                                        FfData ff(&initvals, cell);
 
-                                       if (ff.has_d && !ff.has_clk && !ff.has_en) {
+                                       if (ff.has_gclk) {
                                                // Already a $ff or $_FF_ cell.
                                                continue;
                                        }
@@ -202,25 +202,27 @@ struct Clk2fflogicPass : public Pass {
                                                        qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
                                                else
                                                        qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
-                                       } else if (ff.has_d) {
-
-                                               log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
-                                                               log_id(module), log_id(cell), log_id(cell->type),
-                                                               log_signal(ff.sig_en), log_signal(ff.sig_d), log_signal(ff.sig_q));
+                                       } else {
+                                               if (ff.has_aload) {
+                                                       log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
+                                                                       log_id(module), log_id(cell), log_id(cell->type),
+                                                                       log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_q));
+                                               } else {
+                                                       // $sr.
+                                                       log("Replacing %s.%s (%s): SET=%s, CLR=%s, Q=%s\n",
+                                                                       log_id(module), log_id(cell), log_id(cell->type),
+                                                                       log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_q));
+                                               }
+                                               qval = past_q;
+                                       }
 
-                                               SigSpec sig_en = wrap_async_control(module, ff.sig_en, ff.pol_en);
+                                       if (ff.has_aload) {
+                                               SigSpec sig_aload = wrap_async_control(module, ff.sig_aload, ff.pol_aload);
 
                                                if (!ff.is_fine)
-                                                       qval = module->Mux(NEW_ID, past_q, ff.sig_d, sig_en);
+                                                       qval = module->Mux(NEW_ID, qval, ff.sig_ad, sig_aload);
                                                else
-                                                       qval = module->MuxGate(NEW_ID, past_q, ff.sig_d, sig_en);
-                                       } else {
-
-                                               log("Replacing %s.%s (%s): SET=%s, CLR=%s, Q=%s\n",
-                                                               log_id(module), log_id(cell), log_id(cell->type),
-                                                               log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_q));
-
-                                               qval = past_q;
+                                                       qval = module->MuxGate(NEW_ID, qval, ff.sig_ad, sig_aload);
                                        }
 
                                        if (ff.has_sr) {
index fb107ff75b088450f592ff61acac76cfd499e08f..583185e75bc9e51f8868a89c9f65f3c2844b4e92 100644 (file)
@@ -84,7 +84,7 @@ struct DffunmapPass : public Pass {
                                        continue;
 
                                if (ce_only) {
-                                       if (!ff.has_en)
+                                       if (!ff.has_ce)
                                                continue;
                                        ff.unmap_ce(mod);
                                } else if (srst_only) {
@@ -92,7 +92,7 @@ struct DffunmapPass : public Pass {
                                                continue;
                                        ff.unmap_srst(mod);
                                } else {
-                                       if (!ff.has_en && !ff.has_srst)
+                                       if (!ff.has_ce && !ff.has_srst)
                                                continue;
                                        ff.unmap_ce_srst(mod);
                                }