Added "opt_const -mux_undef"
authorClifford Wolf <clifford@clifford.at>
Tue, 14 Jan 2014 10:10:29 +0000 (11:10 +0100)
committerClifford Wolf <clifford@clifford.at>
Tue, 14 Jan 2014 10:10:29 +0000 (11:10 +0100)
passes/opt/opt_const.cc

index 0ead97b4e3599e4a20d7ab6143a7ff44f97b363a..c5c159ae2003ae6abf8efc424ce71ce51ad947bb 100644 (file)
@@ -42,7 +42,7 @@ void replace_cell(RTLIL::Module *module, RTLIL::Cell *cell, std::string info, st
        did_something = true;
 }
 
-void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x)
+void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef)
 {
        if (!design->selected(module))
                return;
@@ -139,8 +139,16 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
                                cell->connections.erase("\\S");
                                goto next_cell;
                        }
+                       if (input.match("11 ")) ACTION_DO_Y(1);
+                       if (input.match("00 ")) ACTION_DO_Y(0);
+                       if (input.match("** ")) ACTION_DO_Y(x);
                        if (input.match("01*")) ACTION_DO_Y(x);
                        if (input.match("10*")) ACTION_DO_Y(x);
+                       if (mux_undef) {
+                               if (input.match("*  ")) ACTION_DO("\\Y", input.extract(1, 1));
+                               if (input.match(" * ")) ACTION_DO("\\Y", input.extract(2, 1));
+                               if (input.match("  *")) ACTION_DO("\\Y", input.extract(2, 1));
+                       }
                }
 
                if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex")
@@ -216,6 +224,51 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
                        }
                }
 
+               if (mux_undef && (cell->type == "$mux" || cell->type == "$pmux")) {
+                       RTLIL::SigSpec new_a, new_b, new_s;
+                       int width = cell->connections.at("\\A").width;
+                       if ((cell->connections.at("\\A").is_fully_undef() && cell->connections.at("\\B").is_fully_undef()) ||
+                                       cell->connections.at("\\S").is_fully_undef()) {
+                               replace_cell(module, cell, "mux undef", "\\Y", cell->connections.at("\\A"));
+                               goto next_cell;
+                       }
+                       for (int i = 0; i < cell->connections.at("\\S").width; i++) {
+                               RTLIL::SigSpec old_b = cell->connections.at("\\B").extract(i*width, width);
+                               RTLIL::SigSpec old_s = cell->connections.at("\\S").extract(i, 1);
+                               if (old_b.is_fully_undef() || old_s.is_fully_undef())
+                                       continue;
+                               new_b.append(old_b);
+                               new_s.append(old_s);
+                       }
+                       new_a = cell->connections.at("\\A");
+                       if (new_a.is_fully_undef() && new_s.width > 0) {
+                               new_a = new_b.extract((new_s.width-1)*width, width);
+                               new_b = new_b.extract(0, (new_s.width-1)*width);
+                               new_s = new_s.extract(0, new_s.width-1);
+                       }
+                       if (new_s.width == 0) {
+                               replace_cell(module, cell, "mux undef", "\\Y", new_a);
+                               goto next_cell;
+                       }
+                       if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) {
+                               replace_cell(module, cell, "mux undef", "\\Y", new_s);
+                               goto next_cell;
+                       }
+                       if (cell->connections.at("\\S").width != new_s.width) {
+                               cell->connections.at("\\A") = new_a;
+                               cell->connections.at("\\B") = new_b;
+                               cell->connections.at("\\S") = new_s;
+                               if (new_s.width > 1) {
+                                       cell->type = "$pmux";
+                                       cell->parameters["\\S_WIDTH"] = new_s.width;
+                               } else {
+                                       cell->type = "$mux";
+                                       cell->parameters.erase("\\S_WIDTH");
+                               }
+                               did_something = true;
+                       }
+               }
+
 #define FOLD_1ARG_CELL(_t) \
                if (cell->type == "$" #_t) { \
                        RTLIL::SigSpec a = cell->connections["\\A"]; \
@@ -312,25 +365,38 @@ struct OptConstPass : public Pass {
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
                log("\n");
-               log("    opt_const [selection]\n");
+               log("    opt_const [options] [selection]\n");
                log("\n");
                log("This pass performs const folding on internal cell types with constant inputs.\n");
                log("\n");
+               log("    -mux_undef\n");
+               log("        remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
+               log("\n");
        }
        virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
        {
+               bool mux_undef = false;
+
                log_header("Executing OPT_CONST pass (perform const folding).\n");
                log_push();
 
-               extra_args(args, 1, design);
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       if (args[argidx] == "-mux_undef") {
+                               mux_undef = true;
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
 
                for (auto &mod_it : design->modules)
                        do {
                                do {
                                        did_something = false;
-                                       replace_const_cells(design, mod_it.second, false);
+                                       replace_const_cells(design, mod_it.second, false, mux_undef);
                                } while (did_something);
-                               replace_const_cells(design, mod_it.second, true);
+                               replace_const_cells(design, mod_it.second, true, mux_undef);
                        } while (did_something);
 
                log_pop();