Transform "$.*" to ID("$.*") in passes/techmap
[yosys.git] / passes / techmap / dff2dffe.cc
index 1ec4cf5e9280f98a454721b77e30df7a5f5c6abf..044b0a6216a56ccd955e52c7404b9ddad07e758e 100644 (file)
@@ -2,11 +2,11 @@
  *  yosys -- Yosys Open SYnthesis Suite
  *
  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
- *  
+ *
  *  Permission to use, copy, modify, and/or distribute this software for any
  *  purpose with or without fee is hereby granted, provided that the above
  *  copyright notice and this permission notice appear in all copies.
- *  
+ *
  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -52,13 +52,13 @@ struct Dff2dffeWorker
                }
 
                for (auto cell : module->cells()) {
-                       if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_") {
+                       if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) {
                                RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
                                for (int i = 0; i < GetSize(sig_y); i++)
                                        bit2mux[sig_y[i]] = cell_int_t(cell, i);
                        }
                        if (direct_dict.empty()) {
-                               if (cell->type == "$dff" || cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
+                               if (cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_)))
                                        dff_cells.push_back(cell);
                        } else {
                                if (direct_dict.count(cell->type))
@@ -167,7 +167,7 @@ struct Dff2dffeWorker
                }
 
                if (GetSize(or_input) == 0)
-                       return RTLIL::S1;
+                       return State::S1;
 
                if (GetSize(or_input) == 1)
                        return or_input;
@@ -211,13 +211,13 @@ struct Dff2dffeWorker
                                dff_cell->setPort("\\E", make_patterns_logic(it.first, true));
                                dff_cell->type = direct_dict.at(dff_cell->type);
                        } else
-                       if (dff_cell->type == "$dff") {
+                       if (dff_cell->type == ID($dff)) {
                                RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort("\\CLK"), make_patterns_logic(it.first, false),
                                                new_sig_d, new_sig_q, dff_cell->getParam("\\CLK_POLARITY").as_bool(), true);
                                log("  created $dffe cell %s for %s -> %s.\n", log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
                        } else {
                                RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort("\\C"), make_patterns_logic(it.first, true),
-                                               new_sig_d, new_sig_q, dff_cell->type == "$_DFF_P_", true);
+                                               new_sig_d, new_sig_q, dff_cell->type == ID($_DFF_P_), true);
                                log("  created %s cell %s for %s -> %s.\n", log_id(new_cell->type), log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
                        }
                }
@@ -243,15 +243,17 @@ struct Dff2dffeWorker
 
        void run()
        {
-               log("Transforming $dff to $dffe cells in module %s:\n", log_id(module));
-               for (auto dff_cell : dff_cells)
+               log("Transforming FF to FF+Enable cells in module %s:\n", log_id(module));
+               for (auto dff_cell : dff_cells) {
+                       // log("Handling candidate %s:\n", log_id(dff_cell));
                        handle_dff_cell(dff_cell);
+               }
        }
 };
 
 struct Dff2dffePass : public Pass {
        Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { }
-       virtual void help()
+       void help() YS_OVERRIDE
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
                log("\n");
@@ -265,27 +267,33 @@ struct Dff2dffePass : public Pass {
                log("        operate in the opposite direction: replace $dffe cells with combinations\n");
                log("        of $dff and $mux cells. the options below are ignore in unmap mode.\n");
                log("\n");
+               log("    -unmap-mince N\n");
+               log("        Same as -unmap but only unmap $dffe where the clock enable port\n");
+               log("        signal is used by less $dffe than the specified number\n");
+               log("\n");
                log("    -direct <internal_gate_type> <external_gate_type>\n");
                log("        map directly to external gate type. <internal_gate_type> can\n");
                log("        be any internal gate-level FF cell (except $_DFFE_??_). the\n");
                log("        <external_gate_type> is the cell type name for a cell with an\n");
                log("        identical interface to the <internal_gate_type>, except it\n");
                log("        also has an high-active enable port 'E'.\n");
-               log("          Usually <external_gate_type> is an intemediate cell type\n");
+               log("          Usually <external_gate_type> is an intermediate cell type\n");
                log("        that is then translated to the final type using 'techmap'.\n");
                log("\n");
                log("    -direct-match <pattern>\n");
                log("        like -direct for all DFF cell types matching the expression.\n");
                log("        this will use $__DFFE_* as <external_gate_type> matching the\n");
-               log("        internal gate type $_DFF_*_, except for $_DFF_[NP]_, which is\n");
-               log("        converted to $_DFFE_[NP]_.\n");
+               log("        internal gate type $_DFF_*_, and $__DFFSE_* for those matching\n");
+               log("        $_DFFS_*_, except for $_DFF_[NP]_, which is converted to \n");
+               log("        $_DFFE_[NP]_.\n");
                log("\n");
        }
-       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
        {
-               log_header("Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
+               log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
 
                bool unmap_mode = false;
+               int min_ce_use = -1;
                dict<IdString, IdString> direct_dict;
 
                size_t argidx;
@@ -294,6 +302,11 @@ struct Dff2dffePass : public Pass {
                                unmap_mode = true;
                                continue;
                        }
+                       if (args[argidx] == "-unmap-mince" && argidx + 1 < args.size()) {
+                               unmap_mode = true;
+                               min_ce_use = atoi(args[++argidx].c_str());
+                               continue;
+                       }
                        if (args[argidx] == "-direct" && argidx + 2 < args.size()) {
                                string direct_from = RTLIL::escape_id(args[++argidx]);
                                string direct_to = RTLIL::escape_id(args[++argidx]);
@@ -301,29 +314,60 @@ struct Dff2dffePass : public Pass {
                                continue;
                        }
                        if (args[argidx] == "-direct-match" && argidx + 1 < args.size()) {
+                               bool found_match = false;
                                const char *pattern = args[++argidx].c_str();
-                               if (patmatch(pattern, "$_DFF_P_"  ))  direct_dict["$_DFF_P_" ] = "$_DFFE_P_";
-                               if (patmatch(pattern, "$_DFF_N_"  ))  direct_dict["$_DFF_N_" ] = "$_DFFE_N_";
-                               if (patmatch(pattern, "$_DFF_NN0_")) direct_dict["$_DFF_NN0"] = "$__DFFE_NN0";
-                               if (patmatch(pattern, "$_DFF_NN1_")) direct_dict["$_DFF_NN1"] = "$__DFFE_NN1";
-                               if (patmatch(pattern, "$_DFF_NP0_")) direct_dict["$_DFF_NP0"] = "$__DFFE_NP0";
-                               if (patmatch(pattern, "$_DFF_NP1_")) direct_dict["$_DFF_NP1"] = "$__DFFE_NP1";
-                               if (patmatch(pattern, "$_DFF_PN0_")) direct_dict["$_DFF_PN0"] = "$__DFFE_PN0";
-                               if (patmatch(pattern, "$_DFF_PN1_")) direct_dict["$_DFF_PN1"] = "$__DFFE_PN1";
-                               if (patmatch(pattern, "$_DFF_PP0_")) direct_dict["$_DFF_PP0"] = "$__DFFE_PP0";
-                               if (patmatch(pattern, "$_DFF_PP1_")) direct_dict["$_DFF_PP1"] = "$__DFFE_PP1";
+                               if (patmatch(pattern, "$_DFF_P_"  )) found_match = true, direct_dict[ID($_DFF_P_)  ] = ID($_DFFE_PP_);
+                               if (patmatch(pattern, "$_DFF_N_"  )) found_match = true, direct_dict[ID($_DFF_N_)  ] = ID($_DFFE_NP_);
+                               if (patmatch(pattern, "$_DFF_NN0_")) found_match = true, direct_dict[ID($_DFF_NN0_)] = ID($__DFFE_NN0);
+                               if (patmatch(pattern, "$_DFF_NN1_")) found_match = true, direct_dict[ID($_DFF_NN1_)] = ID($__DFFE_NN1);
+                               if (patmatch(pattern, "$_DFF_NP0_")) found_match = true, direct_dict[ID($_DFF_NP0_)] = ID($__DFFE_NP0);
+                               if (patmatch(pattern, "$_DFF_NP1_")) found_match = true, direct_dict[ID($_DFF_NP1_)] = ID($__DFFE_NP1);
+                               if (patmatch(pattern, "$_DFF_PN0_")) found_match = true, direct_dict[ID($_DFF_PN0_)] = ID($__DFFE_PN0);
+                               if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict[ID($_DFF_PN1_)] = ID($__DFFE_PN1);
+                               if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict[ID($_DFF_PP0_)] = ID($__DFFE_PP0);
+                               if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict[ID($_DFF_PP1_)] = ID($__DFFE_PP1);
+
+                               if (patmatch(pattern, "$__DFFS_NN0_")) found_match = true, direct_dict[ID($__DFFS_NN0_)] = ID($__DFFSE_NN0);
+                               if (patmatch(pattern, "$__DFFS_NN1_")) found_match = true, direct_dict[ID($__DFFS_NN1_)] = ID($__DFFSE_NN1);
+                               if (patmatch(pattern, "$__DFFS_NP0_")) found_match = true, direct_dict[ID($__DFFS_NP0_)] = ID($__DFFSE_NP0);
+                               if (patmatch(pattern, "$__DFFS_NP1_")) found_match = true, direct_dict[ID($__DFFS_NP1_)] = ID($__DFFSE_NP1);
+                               if (patmatch(pattern, "$__DFFS_PN0_")) found_match = true, direct_dict[ID($__DFFS_PN0_)] = ID($__DFFSE_PN0);
+                               if (patmatch(pattern, "$__DFFS_PN1_")) found_match = true, direct_dict[ID($__DFFS_PN1_)] = ID($__DFFSE_PN1);
+                               if (patmatch(pattern, "$__DFFS_PP0_")) found_match = true, direct_dict[ID($__DFFS_PP0_)] = ID($__DFFSE_PP0);
+                               if (patmatch(pattern, "$__DFFS_PP1_")) found_match = true, direct_dict[ID($__DFFS_PP1_)] = ID($__DFFSE_PP1);
+                               if (!found_match)
+                                       log_cmd_error("No cell types matched pattern '%s'.\n", pattern);
                                continue;
                        }
                        break;
                }
                extra_args(args, argidx, design);
 
+               if (!direct_dict.empty()) {
+                       log("Selected cell types for direct conversion:\n");
+                       for (auto &it : direct_dict)
+                               log("  %s -> %s\n", log_id(it.first), log_id(it.second));
+               }
+
                for (auto mod : design->selected_modules())
                        if (!mod->has_processes_warn())
                        {
                                if (unmap_mode) {
+                                       SigMap sigmap(mod);
                                        for (auto cell : mod->selected_cells()) {
-                                               if (cell->type == "$dffe") {
+                                               if (cell->type == ID($dffe)) {
+                                                       if (min_ce_use >= 0) {
+                                                               int ce_use = 0;
+                                                               for (auto cell_other : mod->selected_cells()) {
+                                                                       if (cell_other->type != cell->type)
+                                                                               continue;
+                                                                       if (sigmap(cell->getPort("\\EN")) == sigmap(cell_other->getPort("\\EN")))
+                                                                               ce_use++;
+                                                               }
+                                                               if (ce_use >= min_ce_use)
+                                                                       continue;
+                                                       }
+
                                                        RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort("\\D")));
                                                        mod->addDff(NEW_ID, cell->getPort("\\CLK"), tmp, cell->getPort("\\Q"), cell->getParam("\\CLK_POLARITY").as_bool());
                                                        if (cell->getParam("\\EN_POLARITY").as_bool())
@@ -333,9 +377,21 @@ struct Dff2dffePass : public Pass {
                                                        mod->remove(cell);
                                                        continue;
                                                }
-                                               if (cell->type.substr(0, 7) == "$_DFFE_") {
-                                                       bool clk_pol = cell->type.substr(7, 1) == "P";
-                                                       bool en_pol = cell->type.substr(8, 1) == "P";
+                                               if (cell->type.begins_with("$_DFFE_")) {
+                                                       if (min_ce_use >= 0) {
+                                                               int ce_use = 0;
+                                                               for (auto cell_other : mod->selected_cells()) {
+                                                                       if (cell_other->type != cell->type)
+                                                                               continue;
+                                                                       if (sigmap(cell->getPort("\\E")) == sigmap(cell_other->getPort("\\E")))
+                                                                               ce_use++;
+                                                               }
+                                                               if (ce_use >= min_ce_use)
+                                                                       continue;
+                                                       }
+
+                                                       bool clk_pol = cell->type.compare(7, 1, "P") == 0;
+                                                       bool en_pol = cell->type.compare(8, 1, "P") == 0;
                                                        RTLIL::SigSpec tmp = mod->addWire(NEW_ID);
                                                        mod->addDff(NEW_ID, cell->getPort("\\C"), tmp, cell->getPort("\\Q"), clk_pol);
                                                        if (en_pol)
@@ -354,5 +410,5 @@ struct Dff2dffePass : public Pass {
                        }
        }
 } Dff2dffePass;
+
 PRIVATE_NAMESPACE_END