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)
{
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:;
+ }
}
}
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());
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)