Added opt_const -clkinv
authorClifford Wolf <clifford@clifford.at>
Wed, 1 Jul 2015 08:49:21 +0000 (10:49 +0200)
committerClifford Wolf <clifford@clifford.at>
Wed, 1 Jul 2015 08:49:21 +0000 (10:49 +0200)
passes/opt/opt.cc
passes/opt/opt_const.cc

index 76e6fb3657f6de09dffdfa0b2fb9bee2fe4205db..150cacf9a3e31aa4cffc6671c155a2e4c4a0bd24 100644 (file)
@@ -37,7 +37,7 @@ struct OptPass : public Pass {
                log("a series of trivial optimizations and cleanups. This pass executes the other\n");
                log("passes in the following order:\n");
                log("\n");
-               log("    opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]\n");
+               log("    opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
                log("    opt_share [-share_all] -nomux\n");
                log("\n");
                log("    do\n");
@@ -46,13 +46,13 @@ struct OptPass : public Pass {
                log("        opt_share [-share_all]\n");
                log("        opt_rmdff\n");
                log("        opt_clean [-purge]\n");
-               log("        opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]\n");
+               log("        opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
                log("    while <changed design>\n");
                log("\n");
                log("When called with -fast the following script is used instead:\n");
                log("\n");
                log("    do\n");
-               log("        opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]\n");
+               log("        opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
                log("        opt_share [-share_all]\n");
                log("        opt_rmdff\n");
                log("        opt_clean [-purge]\n");
@@ -92,6 +92,10 @@ struct OptPass : public Pass {
                                opt_const_args += " -undriven";
                                continue;
                        }
+                       if (args[argidx] == "-clkinv") {
+                               opt_const_args += " -clkinv";
+                               continue;
+                       }
                        if (args[argidx] == "-fine") {
                                opt_const_args += " -fine";
                                opt_reduce_args += " -fine";
index 859d7c64d61ef96bf94ceb99b6762701bd4540e6..a398089175d807f83378d048a307c1160aa7c79a 100644 (file)
@@ -186,7 +186,49 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
        return true;
 }
 
-void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc)
+void handle_polarity_inv(Cell *cell, IdString port, IdString param, const SigMap &assign_map, const dict<RTLIL::SigSpec, RTLIL::SigSpec> &invert_map)
+{
+       SigSpec sig = assign_map(cell->getPort(port));
+       if (invert_map.count(sig)) {
+               log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
+                               log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module),
+                               log_signal(sig), log_signal(invert_map.at(sig)));
+               cell->setPort(port, (invert_map.at(sig)));
+               cell->setParam(param, !cell->getParam(param).as_bool());
+       }
+}
+
+void handle_clkpol_celltype_swap(Cell *cell, string type1, string type2, IdString port, const SigMap &assign_map, const dict<RTLIL::SigSpec, RTLIL::SigSpec> &invert_map)
+{
+       log_assert(GetSize(type1) == GetSize(type2));
+       string cell_type = cell->type.str();
+
+       if (GetSize(type1) != GetSize(cell_type))
+               return;
+
+       for (int i = 0; i < GetSize(type1); i++) {
+               log_assert((type1[i] == '?') == (type2[i] == '?'));
+               if (type1[i] == '?') {
+                       if (cell_type[i] != '0' && cell_type[i] != '1' && cell_type[i] != 'N' && cell_type[i] != 'P')
+                               return;
+                       type1[i] = cell_type[i];
+                       type2[i] = cell_type[i];
+               }
+       }
+
+       if (cell->type.in(type1, type2)) {
+               SigSpec sig = assign_map(cell->getPort(port));
+               if (invert_map.count(sig)) {
+                       log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
+                                       log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module),
+                                       log_signal(sig), log_signal(invert_map.at(sig)));
+                       cell->setPort(port, (invert_map.at(sig)));
+                       cell->type = cell->type == type1 ? type2 : type1;
+               }
+       }
+}
+
+void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool clkinv)
 {
        if (!design->selected(module))
                return;
@@ -232,6 +274,41 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 #define ACTION_DO(_p_, _s_) do { cover("opt.opt_const.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
 #define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
 
+               if (clkinv)
+               {
+                       if (cell->type.in("$dff", "$dffe", "$dffsr", "$adff", "$fsm", "$memrd", "$memwr"))
+                               handle_polarity_inv(cell, "\\CLK", "\\CLK_POLARITY", assign_map, invert_map);
+
+                       if (cell->type.in("$sr", "$dffsr", "$dlatchsr")) {
+                               handle_polarity_inv(cell, "\\SET", "\\SET_POLARITY", assign_map, invert_map);
+                               handle_polarity_inv(cell, "\\CLR", "\\CLR_POLARITY", assign_map, invert_map);
+                       }
+
+                       if (cell->type.in("$dffe", "$dlatch", "$dlatchsr"))
+                               handle_polarity_inv(cell, "\\EN", "\\EN_POLARITY", assign_map, invert_map);
+
+                       handle_clkpol_celltype_swap(cell, "$_SR_N?_", "$_SR_P?_", "\\S", assign_map, invert_map);
+                       handle_clkpol_celltype_swap(cell, "$_SR_?N_", "$_SR_?P_", "\\R", assign_map, invert_map);
+
+                       handle_clkpol_celltype_swap(cell, "$_DFF_N_", "$_DFF_P_", "\\C", assign_map, invert_map);
+
+                       handle_clkpol_celltype_swap(cell, "$_DFFE_N?_", "$_DFFE_P?_", "\\C", assign_map, invert_map);
+                       handle_clkpol_celltype_swap(cell, "$_DFFE_?N_", "$_DFFE_?P_", "\\E", assign_map, invert_map);
+
+                       handle_clkpol_celltype_swap(cell, "$_DFF_N??_", "$_DFF_P??_", "\\C", assign_map, invert_map);
+                       handle_clkpol_celltype_swap(cell, "$_DFF_?N?_", "$_DFF_?P?_", "\\R", assign_map, invert_map);
+
+                       handle_clkpol_celltype_swap(cell, "$_DFFSR_N??_", "$_DFFSR_P??_", "\\C", assign_map, invert_map);
+                       handle_clkpol_celltype_swap(cell, "$_DFFSR_?N?_", "$_DFFSR_?P?_", "\\S", assign_map, invert_map);
+                       handle_clkpol_celltype_swap(cell, "$_DFFSR_??N_", "$_DFFSR_??P_", "\\R", assign_map, invert_map);
+
+                       handle_clkpol_celltype_swap(cell, "$_DLATCH_N_", "$_DLATCH_P_", "\\E", assign_map, invert_map);
+
+                       handle_clkpol_celltype_swap(cell, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", "\\E", assign_map, invert_map);
+                       handle_clkpol_celltype_swap(cell, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", "\\S", assign_map, invert_map);
+                       handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", "\\R", assign_map, invert_map);
+               }
+
                if (do_fine)
                {
                        if (cell->type == "$not" || cell->type == "$pos" ||
@@ -964,6 +1041,9 @@ struct OptConstPass : public Pass {
                log("    -undriven\n");
                log("        replace undriven nets with undef (x) constants\n");
                log("\n");
+               log("    -clkinv\n");
+               log("        optimize clock inverters by changing FF types\n");
+               log("\n");
                log("    -fine\n");
                log("        perform fine-grain optimizations\n");
                log("\n");
@@ -982,6 +1062,7 @@ struct OptConstPass : public Pass {
                bool mux_undef = false;
                bool mux_bool = false;
                bool undriven = false;
+               bool clkinv = false;
                bool do_fine = false;
                bool keepdc = false;
 
@@ -1002,6 +1083,10 @@ struct OptConstPass : public Pass {
                                undriven = true;
                                continue;
                        }
+                       if (args[argidx] == "-clkinv") {
+                               clkinv = true;
+                               continue;
+                       }
                        if (args[argidx] == "-fine") {
                                do_fine = true;
                                continue;
@@ -1029,11 +1114,11 @@ struct OptConstPass : public Pass {
                        do {
                                do {
                                        did_something = false;
-                                       replace_const_cells(design, module, false, mux_undef, mux_bool, do_fine, keepdc);
+                                       replace_const_cells(design, module, false, mux_undef, mux_bool, do_fine, keepdc, clkinv);
                                        if (did_something)
                                                design->scratchpad_set_bool("opt.did_something", true);
                                } while (did_something);
-                               replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc);
+                               replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv);
                        } while (did_something);
                }