Implemented much better #x select operator
authorClifford Wolf <clifford@clifford.at>
Tue, 5 Mar 2013 11:53:40 +0000 (12:53 +0100)
committerClifford Wolf <clifford@clifford.at>
Tue, 5 Mar 2013 11:53:40 +0000 (12:53 +0100)
kernel/select.cc
passes/extract/extract.cc

index 225c7e8069a9be71c40e25c7c0ccd6f51b663d50..3a3c3013f8b6b49af8b23329a86b609b8727ac9a 100644 (file)
@@ -220,7 +220,30 @@ static void select_op_intersect(RTLIL::Design *design, RTLIL::Selection &lhs, co
                lhs.selected_members.erase(it);
 }
 
-static void select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs)
+namespace {
+       struct expand_rule_t {
+               char mode;
+               std::set<RTLIL::IdString> cell_types, port_names;
+       };
+}
+
+static int parse_comma_list(std::set<RTLIL::IdString> &tokens, std::string str, size_t pos, std::string stopchar)
+{
+       stopchar += ',';
+       while (1) {
+               size_t endpos = str.find_first_of(stopchar, pos);
+               if (endpos == std::string::npos)
+                       endpos = str.size();
+               if (endpos != pos)
+                       tokens.insert(RTLIL::escape_id(str.substr(pos, endpos-pos)));
+               pos = endpos;
+               if (pos == str.size() || str[pos] != ',')
+                       return pos;
+               pos++;
+       }
+}
+
+static void select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::vector<expand_rule_t> &rules)
 {
        for (auto &mod_it : design->modules)
        {
@@ -236,13 +259,31 @@ static void select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs)
 
                for (auto &cell : mod->cells)
                for (auto &conn : cell.second->connections)
-               for (auto &chunk : conn.second.chunks)
-                       if (chunk.wire != NULL) {
-                               if (selected_wires.count(chunk.wire) > 0)
-                                       lhs.selected_members[mod->name].insert(cell.first);
-                               if (lhs.selected_members[mod->name].count(cell.first) > 0)
-                                       lhs.selected_members[mod->name].insert(chunk.wire->name);
+               {
+                       char last_mode = '-';
+                       for (auto &rule : rules) {
+                               last_mode = rule.mode;
+                               if (rule.cell_types.size() > 0 && rule.cell_types.count(cell.second->type))
+                                       continue;
+                               if (rule.port_names.size() > 0 && rule.port_names.count(cell.first))
+                                       continue;
+                               if (rule.mode == '+')
+                                       goto include_match;
+                               else
+                                       goto exclude_match;
                        }
+                       if (last_mode == '+')
+                               goto exclude_match;
+               include_match:
+                       for (auto &chunk : conn.second.chunks)
+                               if (chunk.wire != NULL) {
+                                       if (selected_wires.count(chunk.wire) > 0)
+                                               lhs.selected_members[mod->name].insert(cell.first);
+                                       if (lhs.selected_members[mod->name].count(cell.first) > 0)
+                                               lhs.selected_members[mod->name].insert(chunk.wire->name);
+                               }
+               exclude_match:;
+               }
        }
 }
 
@@ -307,14 +348,38 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
                        select_op_intersect(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
                        work_stack.pop_back();
                } else
-               if (arg == "#x" || arg.substr(0, 3) == "#x:") {
+               if (arg == "#x" || (arg.size() > 2 && arg.substr(0, 2) == "#x" && (arg[2] == ':' || ('0' <= arg[2] && arg[2] <= '9')))) {
                        if (work_stack.size() < 1)
                                log_cmd_error("Must have at least one element on stack for operator #x.\n");
-                       int levels = 1;
+                       size_t pos = 2, levels = 1;
+                       std::vector<expand_rule_t> rules;
+                       if (pos < arg.size() && '0' <= arg[pos] && arg[pos] <= '9') {
+                               size_t endpos = arg.find_first_not_of("0123456789", pos);
+                               if (endpos == std::string::npos)
+                                       endpos = arg.size();
+                               levels = atoi(arg.substr(pos, endpos-pos).c_str());
+                       }
+                       while (pos < arg.size()) {
+                               if (arg[pos] != ':' || pos+1 == arg.size())
+                                       goto syntax_error_x;
+                               pos++;
+                               if (arg[pos] == '+' || arg[pos] == '-') {
+                                       expand_rule_t rule;
+                                       rule.mode = arg[pos++];
+                                       pos = parse_comma_list(rule.cell_types, arg, pos, "[:");
+                                       if (pos < arg.size() && arg[pos] == '[') {
+                                               pos = parse_comma_list(rule.port_names, arg, pos, "]:");
+                                               if (pos < arg.size() && arg[pos] == ']')
+                                                       pos++;
+                                       }
+                               } else
+                       syntax_error_x:
+                                       log_cmd_error("Syntax error in expand operator '%s'.\n", arg.c_str());
+                       }
                        if (arg.size() > 3)
                                levels = std::max(atoi(arg.substr(3).c_str()), 1);
                        while (levels-- > 0)
-                               select_op_expand(design, work_stack.back());
+                               select_op_expand(design, work_stack.back(), rules);
                } else
                        log_cmd_error("Unknown selection operator '%s'.\n", arg.c_str());
                select_filter_active_mod(design, work_stack.back());
@@ -560,9 +625,19 @@ struct SelectPass : public Pass {
                log("    #d\n");
                log("        pop the top set from the stack and subtract it from the new top\n");
                log("\n");
-               log("    #x:<num>\n");
-               log("        expand top set by <num> levels (i.e. select all cells connected\n");
-               log("        to selected wires and select all wires connected to selected cells)\n");
+               log("    #x[<num>][:<rule>[:<rule>..]]\n");
+               log("        expand top set <num> num times accorind to the specified rules.\n");
+               log("        (i.e. select all cells connected to selected wires and select all\n");
+               log("        wires connected to selected cells) The rules specify which cell\n");
+               log("        ports to use for this. the syntax for a rule is a '-' for exclusion\n");
+               log("        and a '+' for inclusion, followed by an optional comma seperated\n");
+               log("        list of cell types followed by an optional comma seperated list of\n");
+               log("        cell ports in square brackets.\n");
+               log("\n");
+               log("Example: the following command selects all wires that are connected to a\n");
+               log("'GATE' input of a 'SWITCH' cell:\n");
+               log("\n");
+               log("    select */t:SWITCH #x:+[GATE] */t:SWITCH #d\n");
                log("\n");
        }
        virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
index 669108612af18c1399f1f45fe4329d275864eb23..62d09523e1abd479cc8c8ccb08d46595251e0041 100644 (file)
@@ -121,6 +121,9 @@ namespace
                                        if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(chunk.wire, chunk.offset)] > max_fanout)
                                                continue;
 
+                                       if (sel && !sel->selected(mod, chunk.wire))
+                                               continue;
+
                                        if (sig_bit_ref.count(chunk) == 0) {
                                                bit_ref_t &bit_ref = sig_bit_ref[chunk];
                                                bit_ref.cell = cell->name;
@@ -308,9 +311,6 @@ struct ExtractPass : public Pass {
                log("integer value. Then this value is used to determine the order in which the pass\n");
                log("tries to map the modules to the design (ascending, default value is 0).\n");
                log("\n");
-               log("This pass operates on whole modules or selected cells from modules. Other\n");
-               log("selected entities (wires, etc.) are ignored.\n");
-               log("\n");
                log("See 'help techmap' for a pass that does the opposite thing.\n");
                log("\n");
        }