Added DFFE support to "abc" pass
authorClifford Wolf <clifford@clifford.at>
Fri, 19 Dec 2014 23:44:03 +0000 (00:44 +0100)
committerClifford Wolf <clifford@clifford.at>
Fri, 19 Dec 2014 23:44:03 +0000 (00:44 +0100)
passes/abc/abc.cc

index 9d6d9457968ebfabed48fe22e93c74f0b8fee875..b1a96dda4ff4592cc3e05c4340368012d9843c24 100644 (file)
@@ -95,8 +95,8 @@ RTLIL::Module *module;
 std::vector<gate_t> signal_list;
 std::map<RTLIL::SigBit, int> signal_map;
 
-bool clk_polarity;
-RTLIL::SigSpec clk_sig;
+bool clk_polarity, en_polarity;
+RTLIL::SigSpec clk_sig, en_sig;
 
 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)
 {
@@ -147,7 +147,24 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
                        return;
                if (clk_sig != assign_map(cell->getPort("\\C")))
                        return;
+               goto matching_dff;
+       }
 
+       if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
+       {
+               if (clk_polarity != (cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_"))
+                       return;
+               if (en_polarity != (cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_"))
+                       return;
+               if (clk_sig != assign_map(cell->getPort("\\C")))
+                       return;
+               if (en_sig != assign_map(cell->getPort("\\E")))
+                       return;
+               goto matching_dff;
+       }
+
+       if (0) {
+       matching_dff:
                RTLIL::SigSpec sig_d = cell->getPort("\\D");
                RTLIL::SigSpec sig_q = cell->getPort("\\Q");
 
@@ -556,6 +573,9 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
        clk_polarity = true;
        clk_sig = RTLIL::SigSpec();
 
+       en_polarity = true;
+       en_sig = RTLIL::SigSpec();
+
        std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
        if (!cleanup)
                tempdir_name[0] = tempdir_name[4] = '_';
@@ -607,6 +627,17 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
        fclose(f);
 
        if (clk_str.empty()) {
+               if (clk_str.find(',') != std::string::npos) {
+                       int pos = clk_str.find(',');
+                       std::string en_str = clk_str.substr(pos+1);
+                       clk_str = clk_str.substr(0, pos);
+                       if (en_str[0] == '!') {
+                               en_polarity = false;
+                               en_str = en_str.substr(1);
+                       }
+                       if (module->wires_.count(RTLIL::escape_id(en_str)) != 0)
+                               en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0));
+               }
                if (clk_str[0] == '!') {
                        clk_polarity = false;
                        clk_str = clk_str.substr(1);
@@ -618,19 +649,34 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
        if (dff_mode && clk_sig.size() == 0)
        {
                int best_dff_counter = 0;
-               std::map<std::pair<bool, RTLIL::SigSpec>, int> dff_counters;
+               typedef std::tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
+               std::map<clkdomain_t, int> dff_counters;
 
                for (auto &it : module->cells_)
                {
                        RTLIL::Cell *cell = it.second;
-                       if (cell->type != "$_DFF_N_" && cell->type != "$_DFF_P_")
+                       clkdomain_t key;
+
+                       if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
+                       {
+                               key = clkdomain_t(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")), true, RTLIL::SigSpec());
+                       }
+                       else
+                       if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
+                       {
+                               bool this_clk_pol = cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_";
+                               bool this_en_pol = cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_";
+                               key = clkdomain_t(this_clk_pol, assign_map(cell->getPort("\\C")), this_en_pol, assign_map(cell->getPort("\\E")));
+                       }
+                       else
                                continue;
 
-                       std::pair<bool, RTLIL::SigSpec> key(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")));
                        if (++dff_counters[key] > best_dff_counter) {
                                best_dff_counter = dff_counters[key];
-                               clk_polarity = key.first;
-                               clk_sig = key.second;
+                               clk_polarity = std::get<0>(key);
+                               clk_sig = std::get<1>(key);
+                               en_polarity = std::get<2>(key);
+                               en_sig = std::get<3>(key);
                        }
                }
        }
@@ -638,13 +684,20 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
        if (dff_mode || !clk_str.empty()) {
                if (clk_sig.size() == 0)
                        log("No (matching) clock domain found. Not extracting any FF cells.\n");
-               else
-                       log("Found (matching) %s clock domain: %s\n", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
+               else {
+                       log("Found (matching) %s clock domain: %s", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
+                       if (en_sig.size() != 0)
+                               log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig));
+                       log("\n");
+               }
        }
 
        if (clk_sig.size() != 0)
                mark_port(clk_sig);
 
+       if (en_sig.size() != 0)
+               mark_port(en_sig);
+
        std::vector<RTLIL::Cell*> cells;
        cells.reserve(module->cells_.size());
        for (auto &it : module->cells_)
@@ -899,7 +952,14 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
                                }
                                if (c->type == "\\DFF") {
                                        log_assert(clk_sig.size() == 1);
-                                       RTLIL::Cell *cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+                                       RTLIL::Cell *cell;
+                                       if (en_sig.size() == 0) {
+                                               cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+                                       } else {
+                                               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("\\E", en_sig);
+                                       }
                                        cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
                                        cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
                                        cell->setPort("\\C", clk_sig);
@@ -924,7 +984,14 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
                                }
                                if (c->type == "\\_dff_") {
                                        log_assert(clk_sig.size() == 1);
-                                       RTLIL::Cell *cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+                                       RTLIL::Cell *cell;
+                                       if (en_sig.size() == 0) {
+                                               cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+                                       } else {
+                                               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("\\E", en_sig);
+                                       }
                                        cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
                                        cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
                                        cell->setPort("\\C", clk_sig);