abc: Add support for FFs with reset in -dff
authorMarcelina Kościelnicka <mwk@0x04.net>
Thu, 7 Apr 2022 01:25:35 +0000 (03:25 +0200)
committerMarcelina Kościelnicka <mwk@0x04.net>
Thu, 7 Apr 2022 13:05:02 +0000 (15:05 +0200)
passes/techmap/abc.cc

index 2c91f3a48cea1e185d5d3151108f9a2340554043..a37b2a0f34a7f1bc2a44b891dc7431454e2ddf36 100644 (file)
@@ -45,6 +45,7 @@
 #include "kernel/sigtools.h"
 #include "kernel/celltypes.h"
 #include "kernel/ffinit.h"
+#include "kernel/ff.h"
 #include "kernel/cost.h"
 #include "kernel/log.h"
 #include <stdlib.h>
@@ -73,6 +74,8 @@ PRIVATE_NAMESPACE_BEGIN
 enum class gate_type_t {
        G_NONE,
        G_FF,
+       G_FF0,
+       G_FF1,
        G_BUF,
        G_NOT,
        G_AND,
@@ -115,10 +118,11 @@ std::vector<gate_t> signal_list;
 std::map<RTLIL::SigBit, int> signal_map;
 FfInitVals initvals;
 pool<std::string> enabled_gates;
-bool recover_init, cmos_cost;
+bool cmos_cost;
+bool had_init;
 
-bool clk_polarity, en_polarity;
-RTLIL::SigSpec clk_sig, en_sig;
+bool clk_polarity, en_polarity, arst_polarity, srst_polarity;
+RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig;
 dict<int, std::string> pi_map, po_map;
 
 int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1)
@@ -165,46 +169,84 @@ void mark_port(RTLIL::SigSpec sig)
 
 void extract_cell(RTLIL::Cell *cell, bool keepff)
 {
-       if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
-       {
-               if (clk_polarity != (cell->type == ID($_DFF_P_)))
+       if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
+               FfData ff(&initvals, cell);
+               gate_type_t type = G(FF);
+               if (!ff.has_clk)
                        return;
-               if (clk_sig != assign_map(cell->getPort(ID::C)))
+               if (ff.has_gclk)
                        return;
-               if (GetSize(en_sig) != 0)
+               if (ff.has_aload)
                        return;
-               goto matching_dff;
-       }
-
-       if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
-       {
-               if (clk_polarity != cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)))
+               if (ff.has_sr)
                        return;
-               if (en_polarity != cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
+               if (!ff.is_fine)
                        return;
-               if (clk_sig != assign_map(cell->getPort(ID::C)))
+               if (clk_polarity != ff.pol_clk)
                        return;
-               if (en_sig != assign_map(cell->getPort(ID::E)))
+               if (clk_sig != assign_map(ff.sig_clk))
                        return;
-               goto matching_dff;
-       }
-
-       if (0) {
-       matching_dff:
-               RTLIL::SigSpec sig_d = cell->getPort(ID::D);
-               RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
+               if (ff.has_ce) {
+                       if (en_polarity != ff.pol_ce)
+                               return;
+                       if (en_sig != assign_map(ff.sig_ce))
+                               return;
+               } else {
+                       if (GetSize(en_sig) != 0)
+                               return;
+               }
+               if (ff.val_init == State::S1) {
+                       type = G(FF1);
+                       had_init = true;
+               } else if (ff.val_init == State::S0) {
+                       type = G(FF0);
+                       had_init = true;
+               }
+               if (ff.has_arst) {
+                       if (arst_polarity != ff.pol_arst)
+                               return;
+                       if (arst_sig != assign_map(ff.sig_arst))
+                               return;
+                       if (ff.val_arst == State::S1) {
+                               if (type == G(FF0))
+                                       return;
+                               type = G(FF1);
+                       } else if (ff.val_arst == State::S0) {
+                               if (type == G(FF1))
+                                       return;
+                               type = G(FF0);
+                       }
+               } else {
+                       if (GetSize(arst_sig) != 0)
+                               return;
+               }
+               if (ff.has_srst) {
+                       if (srst_polarity != ff.pol_srst)
+                               return;
+                       if (srst_sig != assign_map(ff.sig_srst))
+                               return;
+                       if (ff.val_srst == State::S1) {
+                               if (type == G(FF0))
+                                       return;
+                               type = G(FF1);
+                       } else if (ff.val_srst == State::S0) {
+                               if (type == G(FF1))
+                                       return;
+                               type = G(FF0);
+                       }
+               } else {
+                       if (GetSize(srst_sig) != 0)
+                               return;
+               }
 
                if (keepff)
-                       for (auto &c : sig_q.chunks())
+                       for (auto &c : ff.sig_q.chunks())
                                if (c.wire != nullptr)
                                        c.wire->attributes[ID::keep] = 1;
 
-               assign_map.apply(sig_d);
-               assign_map.apply(sig_q);
-
-               map_signal(sig_q, G(FF), map_signal(sig_d));
+               map_signal(ff.sig_q, type, map_signal(ff.sig_d));
 
-               module->remove(cell);
+               ff.remove();
                return;
        }
 
@@ -412,7 +454,7 @@ void handle_loops()
        // dot_f = fopen("test.dot", "w");
 
        for (auto &g : signal_list) {
-               if (g.type == G(NONE) || g.type == G(FF)) {
+               if (g.type == G(NONE) || g.type == G(FF) || g.type == G(FF0) || g.type == G(FF1)) {
                        workpool.insert(g.id);
                } else {
                        if (g.in1 >= 0) {
@@ -667,7 +709,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
        signal_list.clear();
        pi_map.clear();
        po_map.clear();
-       recover_init = false;
 
        if (clk_str != "$")
        {
@@ -676,14 +717,41 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 
                en_polarity = true;
                en_sig = RTLIL::SigSpec();
+
+               arst_polarity = true;
+               arst_sig = RTLIL::SigSpec();
+
+               srst_polarity = true;
+               srst_sig = RTLIL::SigSpec();
        }
 
        if (!clk_str.empty() && clk_str != "$")
        {
+               std::string en_str;
+               std::string arst_str;
+               std::string srst_str;
                if (clk_str.find(',') != std::string::npos) {
                        int pos = clk_str.find(',');
-                       std::string en_str = clk_str.substr(pos+1);
+                       en_str = clk_str.substr(pos+1);
                        clk_str = clk_str.substr(0, pos);
+               }
+               if (en_str.find(',') != std::string::npos) {
+                       int pos = en_str.find(',');
+                       arst_str = en_str.substr(pos+1);
+                       arst_str = en_str.substr(0, pos);
+               }
+               if (arst_str.find(',') != std::string::npos) {
+                       int pos = arst_str.find(',');
+                       srst_str = arst_str.substr(pos+1);
+                       srst_str = arst_str.substr(0, pos);
+               }
+               if (clk_str[0] == '!') {
+                       clk_polarity = false;
+                       clk_str = clk_str.substr(1);
+               }
+               if (module->wire(RTLIL::escape_id(clk_str)) != nullptr)
+                       clk_sig = assign_map(module->wire(RTLIL::escape_id(clk_str)));
+               if (en_str != "") {
                        if (en_str[0] == '!') {
                                en_polarity = false;
                                en_str = en_str.substr(1);
@@ -691,12 +759,22 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
                        if (module->wire(RTLIL::escape_id(en_str)) != nullptr)
                                en_sig = assign_map(module->wire(RTLIL::escape_id(en_str)));
                }
-               if (clk_str[0] == '!') {
-                       clk_polarity = false;
-                       clk_str = clk_str.substr(1);
+               if (arst_str != "") {
+                       if (arst_str[0] == '!') {
+                               arst_polarity = false;
+                               arst_str = arst_str.substr(1);
+                       }
+                       if (module->wire(RTLIL::escape_id(arst_str)) != nullptr)
+                               arst_sig = assign_map(module->wire(RTLIL::escape_id(arst_str)));
+               }
+               if (srst_str != "") {
+                       if (srst_str[0] == '!') {
+                               srst_polarity = false;
+                               srst_str = srst_str.substr(1);
+                       }
+                       if (module->wire(RTLIL::escape_id(srst_str)) != nullptr)
+                               srst_sig = assign_map(module->wire(RTLIL::escape_id(srst_str)));
                }
-               if (module->wire(RTLIL::escape_id(clk_str)) != nullptr)
-                       clk_sig = assign_map(module->wire(RTLIL::escape_id(clk_str)));
        }
 
        if (dff_mode && clk_sig.empty())
@@ -789,10 +867,15 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
                        log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
                        if (en_sig.size() != 0)
                                log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig));
+                       if (arst_sig.size() != 0)
+                               log(", asynchronously reset by %s%s", arst_polarity ? "" : "!", log_signal(arst_sig));
+                       if (srst_sig.size() != 0)
+                               log(", synchronously reset by %s%s", srst_polarity ? "" : "!", log_signal(srst_sig));
                        log("\n");
                }
        }
 
+       had_init = false;
        for (auto c : cells)
                extract_cell(c, keepff);
 
@@ -811,6 +894,12 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
        if (en_sig.size() != 0)
                mark_port(en_sig);
 
+       if (arst_sig.size() != 0)
+               mark_port(arst_sig);
+
+       if (srst_sig.size() != 0)
+               mark_port(srst_sig);
+
        handle_loops();
 
        buffer = stringf("%s/input.blif", tempdir_name.c_str());
@@ -917,11 +1006,11 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
                        fprintf(f, "00-- 1\n");
                        fprintf(f, "--00 1\n");
                } else if (si.type == G(FF)) {
-                       if (si.init == State::S0 || si.init == State::S1) {
-                               fprintf(f, ".latch ys__n%d ys__n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0);
-                               recover_init = true;
-                       } else
-                               fprintf(f, ".latch ys__n%d ys__n%d 2\n", si.in1, si.id);
+                       fprintf(f, ".latch ys__n%d ys__n%d 2\n", si.in1, si.id);
+               } else if (si.type == G(FF0)) {
+                       fprintf(f, ".latch ys__n%d ys__n%d 0\n", si.in1, si.id);
+               } else if (si.type == G(FF1)) {
+                       fprintf(f, ".latch ys__n%d ys__n%d 1\n", si.in1, si.id);
                } else if (si.type != G(NONE))
                        log_abort();
                if (si.type != G(NONE))
@@ -1043,6 +1132,9 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
                        design->select(module, wire);
                }
 
+               SigMap mapped_sigmap(mapped_mod);
+               FfInitVals mapped_initvals(&mapped_sigmap, mapped_mod);
+
                std::map<std::string, int> cell_stats;
                for (auto c : mapped_mod->cells())
                {
@@ -1149,20 +1241,41 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
                                }
                                if (c->type == ID(DFF)) {
                                        log_assert(clk_sig.size() == 1);
-                                       RTLIL::Cell *cell;
-                                       if (en_sig.size() == 0) {
-                                               cell = module->addCell(remap_name(c->name), clk_polarity ? ID($_DFF_P_) : ID($_DFF_N_));
-                                       } else {
+                                       FfData ff(module, &initvals, remap_name(c->name));
+                                       ff.width = 1;
+                                       ff.is_fine = true;
+                                       ff.has_clk = true;
+                                       ff.pol_clk = clk_polarity;
+                                       ff.sig_clk = clk_sig;
+                                       if (en_sig.size() != 0) {
                                                log_assert(en_sig.size() == 1);
-                                               cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
-                                               cell->setPort(ID::E, en_sig);
+                                               ff.has_ce = true;
+                                               ff.pol_ce = en_polarity;
+                                               ff.sig_ce = en_sig;
                                        }
-                                       if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
-                                       for (auto name : {ID::D, ID::Q}) {
-                                               RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
-                                               cell->setPort(name, module->wire(remapped_name));
+                                       RTLIL::Const init = mapped_initvals(c->getPort(ID::Q));
+                                       if (had_init)
+                                               ff.val_init = init;
+                                       else
+                                               ff.val_init = State::Sx;
+                                       if (arst_sig.size() != 0) {
+                                               log_assert(arst_sig.size() == 1);
+                                               ff.has_arst = true;
+                                               ff.pol_arst = arst_polarity;
+                                               ff.sig_arst = arst_sig;
+                                               ff.val_arst = init;
                                        }
-                                       cell->setPort(ID::C, clk_sig);
+                                       if (srst_sig.size() != 0) {
+                                               log_assert(srst_sig.size() == 1);
+                                               ff.has_srst = true;
+                                               ff.pol_srst = srst_polarity;
+                                               ff.sig_srst = srst_sig;
+                                               ff.val_srst = init;
+                                       }
+                                       ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name));
+                                       ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name));
+                                       RTLIL::Cell *cell = ff.emit();
+                                       if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
                                        design->select(module, cell);
                                        continue;
                                }
@@ -1180,20 +1293,38 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 
                        if (c->type == ID(_dff_)) {
                                log_assert(clk_sig.size() == 1);
-                               RTLIL::Cell *cell;
-                               if (en_sig.size() == 0) {
-                                       cell = module->addCell(remap_name(c->name), clk_polarity ? ID($_DFF_P_) : ID($_DFF_N_));
-                               } else {
+                               FfData ff(module, &initvals, remap_name(c->name));
+                               ff.width = 1;
+                               ff.is_fine = true;
+                               ff.has_clk = true;
+                               ff.pol_clk = clk_polarity;
+                               ff.sig_clk = clk_sig;
+                               if (en_sig.size() != 0) {
                                        log_assert(en_sig.size() == 1);
-                                       cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
-                                       cell->setPort(ID::E, en_sig);
+                                       ff.pol_ce = en_polarity;
+                                       ff.sig_ce = en_sig;
                                }
-                               if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
-                               for (auto name : {ID::D, ID::Q}) {
-                                       RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
-                                       cell->setPort(name, module->wire(remapped_name));
+                               RTLIL::Const init = mapped_initvals(c->getPort(ID::Q));
+                               if (had_init)
+                                       ff.val_init = init;
+                               else
+                                       ff.val_init = State::Sx;
+                               if (arst_sig.size() != 0) {
+                                       log_assert(arst_sig.size() == 1);
+                                       ff.pol_arst = arst_polarity;
+                                       ff.sig_arst = arst_sig;
+                                       ff.val_arst = init;
+                               }
+                               if (srst_sig.size() != 0) {
+                                       log_assert(srst_sig.size() == 1);
+                                       ff.pol_srst = srst_polarity;
+                                       ff.sig_srst = srst_sig;
+                                       ff.val_srst = init;
                                }
-                               cell->setPort(ID::C, clk_sig);
+                               ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name));
+                               ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name));
+                               RTLIL::Cell *cell = ff.emit();
+                               if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
                                design->select(module, cell);
                                continue;
                        }
@@ -1229,15 +1360,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
                        module->connect(conn);
                }
 
-               if (recover_init)
-                       for (auto wire : mapped_mod->wires()) {
-                               if (wire->attributes.count(ID::init)) {
-                                       Wire *w = module->wire(remap_name(wire->name));
-                                       log_assert(w->attributes.count(ID::init) == 0);
-                                       w->attributes[ID::init] = wire->attributes.at(ID::init);
-                               }
-                       }
-
                for (auto &it : cell_stats)
                        log("ABC RESULTS:   %15s cells: %8d\n", it.first.c_str(), it.second);
                int in_wires = 0, out_wires = 0;
@@ -1884,7 +2006,7 @@ struct AbcPass : public Pass {
                        std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
                        std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
 
-                       typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
+                       typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec, bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
                        std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
                        std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
 
@@ -1912,19 +2034,30 @@ struct AbcPass : public Pass {
                                        }
                                }
 
-                               if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
-                               {
-                                       key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID::C)), true, RTLIL::SigSpec());
-                               }
-                               else
-                               if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
-                               {
-                                       bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_));
-                                       bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_));
-                                       key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID::C)), this_en_pol, assign_map(cell->getPort(ID::E)));
-                               }
-                               else
+                               if (!RTLIL::builtin_ff_cell_types().count(cell->type))
+                                       continue;
+
+                               FfData ff(&initvals, cell);
+                               if (!ff.has_clk)
+                                       continue;
+                               if (ff.has_gclk)
+                                       continue;
+                               if (ff.has_aload)
+                                       continue;
+                               if (ff.has_sr)
+                                       continue;
+                               if (!ff.is_fine)
                                        continue;
+                               key = clkdomain_t(
+                                       ff.pol_clk,
+                                       ff.sig_clk,
+                                       ff.has_ce ? ff.pol_ce : true,
+                                       ff.has_ce ? assign_map(ff.sig_ce) : RTLIL::SigSpec(),
+                                       ff.has_arst ? ff.pol_arst : true,
+                                       ff.has_arst ? assign_map(ff.sig_arst) : RTLIL::SigSpec(),
+                                       ff.has_srst ? ff.pol_srst : true,
+                                       ff.has_srst ? assign_map(ff.sig_srst) : RTLIL::SigSpec()
+                               );
 
                                unassigned_cells.erase(cell);
                                expand_queue.insert(cell);
@@ -1998,7 +2131,7 @@ struct AbcPass : public Pass {
                                        expand_queue.swap(next_expand_queue);
                        }
 
-                       clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
+                       clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec(), true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
                        for (auto cell : unassigned_cells) {
                                assigned_cells[key].push_back(cell);
                                assigned_cells_reverse[cell] = key;
@@ -2006,15 +2139,21 @@ struct AbcPass : public Pass {
 
                        log_header(design, "Summary of detected clock domains:\n");
                        for (auto &it : assigned_cells)
-                               log("  %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
+                               log("  %d cells in clk=%s%s, en=%s%s, arst=%s%s, srst=%s%s\n", GetSize(it.second),
                                                std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
-                                               std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
+                                               std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)),
+                                               std::get<4>(it.first) ? "" : "!", log_signal(std::get<5>(it.first)),
+                                               std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first)));
 
                        for (auto &it : assigned_cells) {
                                clk_polarity = std::get<0>(it.first);
                                clk_sig = assign_map(std::get<1>(it.first));
                                en_polarity = std::get<2>(it.first);
                                en_sig = assign_map(std::get<3>(it.first));
+                               arst_polarity = std::get<4>(it.first);
+                               arst_sig = assign_map(std::get<5>(it.first));
+                               srst_polarity = std::get<6>(it.first);
+                               srst_sig = assign_map(std::get<7>(it.first));
                                abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
                                                keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress);
                                assign_map.set(mod);