diff options
Diffstat (limited to 'passes/cmds/select.cc')
-rw-r--r-- | passes/cmds/select.cc | 223 |
1 files changed, 153 insertions, 70 deletions
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index 4c540ca67..53ff4d475 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -17,14 +17,15 @@ * */ -#include "kernel/register.h" +#include "kernel/yosys.h" #include "kernel/celltypes.h" #include "kernel/sigtools.h" -#include "kernel/log.h" #include <string.h> -#include <fnmatch.h> #include <errno.h> +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + using RTLIL::id2cstr; static std::vector<RTLIL::Selection> work_stack; @@ -35,9 +36,9 @@ static bool match_ids(RTLIL::IdString id, std::string pattern) return true; if (id.size() > 0 && id[0] == '\\' && id.substr(1) == pattern) return true; - if (!fnmatch(pattern.c_str(), id.c_str(), 0)) + if (patmatch(pattern.c_str(), id.c_str())) return true; - if (id.size() > 0 && id[0] == '\\' && !fnmatch(pattern.c_str(), id.substr(1).c_str(), 0)) + if (id.size() > 0 && id[0] == '\\' && patmatch(pattern.c_str(), id.substr(1).c_str())) return true; if (id.size() > 0 && id[0] == '$' && pattern.size() > 0 && pattern[0] == '$') { const char *p = id.c_str(); @@ -80,7 +81,7 @@ static bool match_attr_val(const RTLIL::Const &value, std::string pattern, char std::string value_str = value.decode_string(); if (match_op == '=') - if (!fnmatch(pattern.c_str(), value.decode_string().c_str(), FNM_NOESCAPE)) + if (patmatch(pattern.c_str(), value.decode_string().c_str())) return true; if (match_op == '=') @@ -100,13 +101,13 @@ static bool match_attr_val(const RTLIL::Const &value, std::string pattern, char log_abort(); } -static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes, std::string name_pat, std::string value_pat, char match_op) +static bool match_attr(const dict<RTLIL::IdString, RTLIL::Const> &attributes, std::string name_pat, std::string value_pat, char match_op) { if (name_pat.find('*') != std::string::npos || name_pat.find('?') != std::string::npos || name_pat.find('[') != std::string::npos) { for (auto &it : attributes) { - if (!fnmatch(name_pat.c_str(), it.first.c_str(), FNM_NOESCAPE) && match_attr_val(it.second, value_pat, match_op)) + if (patmatch(name_pat.c_str(), it.first.c_str()) && match_attr_val(it.second, value_pat, match_op)) return true; - if (it.first.size() > 0 && it.first[0] == '\\' && !fnmatch(name_pat.c_str(), it.first.substr(1).c_str(), FNM_NOESCAPE) && match_attr_val(it.second, value_pat, match_op)) + if (it.first.size() > 0 && it.first[0] == '\\' && patmatch(name_pat.c_str(), it.first.substr(1).c_str()) && match_attr_val(it.second, value_pat, match_op)) return true; } } else { @@ -118,7 +119,7 @@ static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes return false; } -static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes, std::string match_expr) +static bool match_attr(const dict<RTLIL::IdString, RTLIL::Const> &attributes, std::string match_expr) { size_t pos = match_expr.find_first_of("<!=>"); @@ -364,7 +365,7 @@ static int parse_comma_list(std::set<RTLIL::IdString> &tokens, std::string str, } } -static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::vector<expand_rule_t> &rules, std::set<RTLIL::IdString> &limits, int max_objects, char mode, CellTypes &ct) +static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::vector<expand_rule_t> &rules, std::set<RTLIL::IdString> &limits, int max_objects, char mode, CellTypes &ct, bool eval_only) { int sel_objects = 0; bool is_input, is_output; @@ -375,6 +376,7 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v RTLIL::Module *mod = mod_it.second; std::set<RTLIL::Wire*> selected_wires; + auto selected_members = lhs.selected_members[mod->name]; for (auto &it : mod->wires_) if (lhs.selected_member(mod_it.first, it.first) && limits.count(it.first) == 0) @@ -388,9 +390,9 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v for (size_t i = 0; i < conn_lhs.size(); i++) { if (conn_lhs[i].wire == NULL || conn_rhs[i].wire == NULL) continue; - if (mode != 'i' && selected_wires.count(conn_rhs[i].wire) && lhs.selected_members[mod->name].count(conn_lhs[i].wire->name) == 0) + if (mode != 'i' && selected_wires.count(conn_rhs[i].wire) && selected_members.count(conn_lhs[i].wire->name) == 0) lhs.selected_members[mod->name].insert(conn_lhs[i].wire->name), sel_objects++, max_objects--; - if (mode != 'o' && selected_wires.count(conn_lhs[i].wire) && lhs.selected_members[mod->name].count(conn_rhs[i].wire->name) == 0) + if (mode != 'o' && selected_wires.count(conn_lhs[i].wire) && selected_members.count(conn_rhs[i].wire->name) == 0) lhs.selected_members[mod->name].insert(conn_rhs[i].wire->name), sel_objects++, max_objects--; } } @@ -399,6 +401,8 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v for (auto &conn : cell.second->connections()) { char last_mode = '-'; + if (eval_only && !yosys_celltypes.cell_evaluable(cell.second->type)) + goto exclude_match; for (auto &rule : rules) { last_mode = rule.mode; if (rule.cell_types.size() > 0 && rule.cell_types.count(cell.second->type) == 0) @@ -417,10 +421,10 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v is_output = mode == 'x' || ct.cell_output(cell.second->type, conn.first); for (auto &chunk : conn.second.chunks()) if (chunk.wire != NULL) { - if (max_objects != 0 && selected_wires.count(chunk.wire) > 0 && lhs.selected_members[mod->name].count(cell.first) == 0) + if (max_objects != 0 && selected_wires.count(chunk.wire) > 0 && selected_members.count(cell.first) == 0) if (mode == 'x' || (mode == 'i' && is_output) || (mode == 'o' && is_input)) lhs.selected_members[mod->name].insert(cell.first), sel_objects++, max_objects--; - if (max_objects != 0 && lhs.selected_members[mod->name].count(cell.first) > 0 && limits.count(cell.first) == 0 && lhs.selected_members[mod->name].count(chunk.wire->name) == 0) + if (max_objects != 0 && selected_members.count(cell.first) > 0 && limits.count(cell.first) == 0 && selected_members.count(chunk.wire->name) == 0) if (mode == 'x' || (mode == 'i' && is_input) || (mode == 'o' && is_output)) lhs.selected_members[mod->name].insert(chunk.wire->name), sel_objects++, max_objects--; } @@ -431,9 +435,10 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v return sel_objects; } -static void select_op_expand(RTLIL::Design *design, std::string arg, char mode) +static void select_op_expand(RTLIL::Design *design, std::string arg, char mode, bool eval_only) { - int pos = mode == 'x' ? 2 : 3, levels = 1, rem_objects = -1; + int pos = (mode == 'x' ? 2 : 3) + (eval_only ? 1 : 0); + int levels = 1, rem_objects = -1; std::vector<expand_rule_t> rules; std::set<RTLIL::IdString> limits; @@ -524,14 +529,14 @@ static void select_op_expand(RTLIL::Design *design, std::string arg, char mode) #endif while (levels-- > 0 && rem_objects != 0) { - int num_objects = select_op_expand(design, work_stack.back(), rules, limits, rem_objects, mode, ct); + int num_objects = select_op_expand(design, work_stack.back(), rules, limits, rem_objects, mode, ct, eval_only); if (num_objects == 0) break; rem_objects -= num_objects; } if (rem_objects == 0) - log("Warning: reached configured limit at `%s'.\n", arg.c_str()); + log_warning("reached configured limit at `%s'.\n", arg.c_str()); } static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &sel) @@ -631,17 +636,32 @@ static void select_stmt(RTLIL::Design *design, std::string arg) if (arg == "%x" || (arg.size() > 2 && arg.substr(0, 2) == "%x" && (arg[2] == ':' || arg[2] == '*' || arg[2] == '.' || ('0' <= arg[2] && arg[2] <= '9')))) { if (work_stack.size() < 1) log_cmd_error("Must have at least one element on the stack for operator %%x.\n"); - select_op_expand(design, arg, 'x'); + select_op_expand(design, arg, 'x', false); } else if (arg == "%ci" || (arg.size() > 3 && arg.substr(0, 3) == "%ci" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) { if (work_stack.size() < 1) log_cmd_error("Must have at least one element on the stack for operator %%ci.\n"); - select_op_expand(design, arg, 'i'); + select_op_expand(design, arg, 'i', false); } else if (arg == "%co" || (arg.size() > 3 && arg.substr(0, 3) == "%co" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) { if (work_stack.size() < 1) log_cmd_error("Must have at least one element on the stack for operator %%co.\n"); - select_op_expand(design, arg, 'o'); + select_op_expand(design, arg, 'o', false); + } else + if (arg == "%xe" || (arg.size() > 3 && arg.substr(0, 3) == "%x" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) { + if (work_stack.size() < 1) + log_cmd_error("Must have at least one element on the stack for operator %%xe.\n"); + select_op_expand(design, arg, 'x', true); + } else + if (arg == "%cie" || (arg.size() > 4 && arg.substr(0, 4) == "%cie" && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) { + if (work_stack.size() < 1) + log_cmd_error("Must have at least one element on the stack for operator %%cie.\n"); + select_op_expand(design, arg, 'i', true); + } else + if (arg == "%coe" || (arg.size() > 4 && arg.substr(0, 4) == "%coe" && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) { + if (work_stack.size() < 1) + log_cmd_error("Must have at least one element on the stack for operator %%coe.\n"); + select_op_expand(design, arg, 'o', true); } else log_cmd_error("Unknown selection operator '%s'.\n", arg.c_str()); if (work_stack.size() >= 1) @@ -795,8 +815,11 @@ static void select_stmt(RTLIL::Design *design, std::string arg) select_filter_active_mod(design, work_stack.back()); } +PRIVATE_NAMESPACE_END +YOSYS_NAMESPACE_BEGIN + // used in kernel/register.cc and maybe other locations, extern decl. in register.h -void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, size_t args_size, RTLIL::Design *design) +void handle_extra_select_args(Pass *pass, vector<string> args, size_t argidx, size_t args_size, RTLIL::Design *design) { work_stack.clear(); for (; argidx < args_size; argidx++) { @@ -812,20 +835,46 @@ void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t select_op_union(design, work_stack.front(), work_stack.back()); work_stack.pop_back(); } - if (work_stack.size() > 0) - design->selection_stack.push_back(work_stack.back()); - else + if (work_stack.empty()) design->selection_stack.push_back(RTLIL::Selection(false)); + else + design->selection_stack.push_back(work_stack.back()); } +// extern decl. in register.h +RTLIL::Selection eval_select_args(const vector<string> &args, RTLIL::Design *design) +{ + work_stack.clear(); + for (auto &arg : args) + select_stmt(design, arg); + while (work_stack.size() > 1) { + select_op_union(design, work_stack.front(), work_stack.back()); + work_stack.pop_back(); + } + if (work_stack.empty()) + return RTLIL::Selection(false); + return work_stack.back(); +} + +// extern decl. in register.h +void eval_select_op(vector<RTLIL::Selection> &work, const string &op, RTLIL::Design *design) +{ + work_stack.swap(work); + select_stmt(design, op); + work_stack.swap(work); +} + +YOSYS_NAMESPACE_END +PRIVATE_NAMESPACE_BEGIN + struct SelectPass : public Pass { SelectPass() : Pass("select", "modify and view the list of selected objects") { } virtual void help() { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" select [ -add | -del | -set <name> ] <selection>\n"); - log(" select [ -assert-none | -assert-any ] <selection>\n"); + log(" select [ -add | -del | -set <name> ] {-read <filename> | <selection>}\n"); + log(" select [ -assert-none | -assert-any ] {-read <filename> | <selection>}\n"); log(" select [ -list | -write <filename> | -count | -clear ]\n"); log(" select -module <modname>\n"); log("\n"); @@ -867,6 +916,9 @@ struct SelectPass : public Pass { log(" -write <filename>\n"); log(" like -list but write the output to the specified file\n"); log("\n"); + log(" -read <filename>\n"); + log(" read the specified file (written by -write)\n"); + log("\n"); log(" -count\n"); log(" count all objects in the current selection\n"); log("\n"); @@ -997,6 +1049,9 @@ struct SelectPass : public Pass { log(" %%co[<num1>|*][.<num2>][:<rule>[:<rule>..]]\n"); log(" simmilar to %%x, but only select input (%%ci) or output cones (%%co)\n"); log("\n"); + log(" %%xe[...] %%cie[...] %%coe\n"); + log(" like %%x, %%ci, and %%co but only consider combinatorial cells\n"); + log("\n"); log(" %%a\n"); log(" expand top set by selecting all wires that are (at least in part)\n"); log(" aliases for selected wires.\n"); @@ -1026,9 +1081,8 @@ struct SelectPass : public Pass { bool assert_none = false; bool assert_any = false; int assert_count = -1; - std::string write_file; - std::string set_name; - std::string sel_str; + std::string write_file, read_file; + std::string set_name, sel_str; work_stack.clear(); @@ -1072,6 +1126,10 @@ struct SelectPass : public Pass { write_file = args[++argidx]; continue; } + if (arg == "-read" && argidx+1 < args.size()) { + read_file = args[++argidx]; + continue; + } if (arg == "-count") { count_mode = true; continue; @@ -1094,6 +1152,34 @@ struct SelectPass : public Pass { sel_str += " " + arg; } + if (!read_file.empty()) + { + if (!sel_str.empty()) + log_cmd_error("Option -read can not be combined with a selection expression.\n"); + + std::ifstream f(read_file); + if (f.fail()) + log_error("Can't open '%s' for reading: %s\n", read_file.c_str(), strerror(errno)); + + RTLIL::Selection sel(false); + string line; + + while (std::getline(f, line)) { + size_t slash_pos = line.find('/'); + if (slash_pos == string::npos) { + log_warning("Ignoring line without slash in 'select -read': %s\n", line.c_str()); + continue; + } + IdString mod_name = RTLIL::escape_id(line.substr(0, slash_pos)); + IdString obj_name = RTLIL::escape_id(line.substr(slash_pos+1)); + sel.selected_members[mod_name].insert(obj_name); + } + + select_filter_active_mod(design, sel); + sel.optimize(design); + work_stack.push_back(sel); + } + if (clear_mode && args.size() != 2) log_cmd_error("Option -clear can not be combined with any other options.\n"); @@ -1135,7 +1221,7 @@ struct SelectPass : public Pass { if (list_mode || count_mode || !write_file.empty()) { - #define LOG_OBJECT(...) do { if (list_mode) log(__VA_ARGS__); if (f != NULL) fprintf(f, __VA_ARGS__); total_count++; } while (0) + #define LOG_OBJECT(...) { if (list_mode) log(__VA_ARGS__); if (f != NULL) fprintf(f, __VA_ARGS__); total_count++; } int total_count = 0; FILE *f = NULL; if (!write_file.empty()) { @@ -1154,16 +1240,16 @@ struct SelectPass : public Pass { if (sel->selected_module(mod_it.first)) { for (auto &it : mod_it.second->wires_) if (sel->selected_member(mod_it.first, it.first)) - LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); + LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)) for (auto &it : mod_it.second->memories) if (sel->selected_member(mod_it.first, it.first)) - LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); + LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)) for (auto &it : mod_it.second->cells_) if (sel->selected_member(mod_it.first, it.first)) - LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); + LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)) for (auto &it : mod_it.second->processes) if (sel->selected_member(mod_it.first, it.first)) - LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); + LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)) } } if (count_mode) @@ -1320,21 +1406,20 @@ struct CdPass : public Pass { } CdPass; template<typename T> -static int log_matches(const char *title, std::string pattern, T list) +static void log_matches(const char *title, Module *module, T list) { - std::vector<RTLIL::IdString> matches; + std::vector<IdString> matches; for (auto &it : list) - if (pattern.empty() || match_ids(it.first, pattern)) + if (module->selected(it.second)) matches.push_back(it.first); - if (matches.empty()) - return 0; - - log("\n%d %s:\n", int(matches.size()), title); - for (auto &id : matches) - log(" %s\n", RTLIL::id2cstr(id)); - return matches.size(); + if (!matches.empty()) { + log("\n%d %s:\n", int(matches.size()), title); + std::sort(matches.begin(), matches.end(), RTLIL::sort_by_id_str()); + for (auto id : matches) + log(" %s\n", RTLIL::id2cstr(id)); + } } struct LsPass : public Pass { @@ -1343,44 +1428,42 @@ struct LsPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" ls [pattern]\n"); + log(" ls [selection]\n"); log("\n"); - log("When no active module is selected, this prints a list of all modules.\n"); + log("When no active module is selected, this prints a list of modules.\n"); log("\n"); log("When an active module is selected, this prints a list of objects in the module.\n"); log("\n"); - log("If a pattern is given, the objects matching the pattern are printed\n"); - log("\n"); - log("Note that this command does not use the selection mechanism and always operates\n"); - log("on the whole design or whole active module. Use 'select -list' to show a list\n"); - log("of currently selected objects.\n"); - log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - std::string pattern; - int counter = 0; - - if (args.size() != 1 && args.size() != 2) - log_cmd_error("Invalid number of arguments.\n"); - if (args.size() == 2) - pattern = args.at(1); + size_t argidx = 1; + extra_args(args, argidx, design); if (design->selected_active_module.empty()) { - counter += log_matches("modules", pattern, design->modules_); + std::vector<IdString> matches; + + for (auto mod : design->selected_modules()) + matches.push_back(mod->name); + + if (!matches.empty()) { + log("\n%d %s:\n", int(matches.size()), "modules"); + std::sort(matches.begin(), matches.end(), RTLIL::sort_by_id_str()); + for (auto id : matches) + log(" %s%s\n", log_id(id), design->selected_whole_module(design->module(id)) ? "" : "*"); + } } else - if (design->modules_.count(design->selected_active_module) > 0) + if (design->module(design->selected_active_module) != nullptr) { - RTLIL::Module *module = design->modules_.at(design->selected_active_module); - counter += log_matches("wires", pattern, module->wires_); - counter += log_matches("memories", pattern, module->memories); - counter += log_matches("cells", pattern, module->cells_); - counter += log_matches("processes", pattern, module->processes); + RTLIL::Module *module = design->module(design->selected_active_module); + log_matches("wires", module, module->wires_); + log_matches("memories", module, module->memories); + log_matches("cells", module, module->cells_); + log_matches("processes", module, module->processes); } - - // log("\nfound %d item%s.\n", counter, counter == 1 ? "" : "s"); } } LsPass; +PRIVATE_NAMESPACE_END |