aboutsummaryrefslogtreecommitdiffstats
path: root/passes/cmds/select.cc
diff options
context:
space:
mode:
Diffstat (limited to 'passes/cmds/select.cc')
-rw-r--r--passes/cmds/select.cc223
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