aboutsummaryrefslogtreecommitdiffstats
path: root/passes/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'passes/cmds')
-rw-r--r--passes/cmds/Makefile.inc1
-rw-r--r--passes/cmds/add.cc4
-rw-r--r--passes/cmds/design.cc3
-rw-r--r--passes/cmds/exec.cc205
-rw-r--r--passes/cmds/select.cc61
5 files changed, 261 insertions, 13 deletions
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index 20b38bf8e..60f20fa6d 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -1,4 +1,5 @@
+OBJS += passes/cmds/exec.o
OBJS += passes/cmds/add.o
OBJS += passes/cmds/delete.o
OBJS += passes/cmds/design.o
diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc
index 7b76f3d4a..c49b8bf5d 100644
--- a/passes/cmds/add.cc
+++ b/passes/cmds/add.cc
@@ -206,6 +206,7 @@ struct AddPass : public Pass {
extra_args(args, argidx, design);
+ bool selected_anything = false;
for (auto module : design->modules())
{
log_assert(module != nullptr);
@@ -214,11 +215,14 @@ struct AddPass : public Pass {
if (module->get_bool_attribute("\\blackbox"))
continue;
+ selected_anything = true;
if (is_formal_celltype(command))
add_formal(module, command, arg_name, enable_name);
else if (command == "wire")
add_wire(design, module, arg_name, arg_width, arg_flag_input, arg_flag_output, arg_flag_global);
}
+ if (!selected_anything)
+ log_warning("No modules selected, or only blackboxes. Nothing was added.\n");
}
} AddPass;
diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc
index 172addcc1..fab23fc1d 100644
--- a/passes/cmds/design.cc
+++ b/passes/cmds/design.cc
@@ -18,6 +18,7 @@
*/
#include "kernel/yosys.h"
+#include "frontends/verilog/preproc.h"
#include "frontends/ast/ast.h"
YOSYS_NAMESPACE_BEGIN
@@ -346,7 +347,7 @@ struct DesignPass : public Pass {
delete node;
design->verilog_globals.clear();
- design->verilog_defines.clear();
+ design->verilog_defines->clear();
}
if (!load_name.empty() || pop_mode)
diff --git a/passes/cmds/exec.cc b/passes/cmds/exec.cc
new file mode 100644
index 000000000..7eeefe705
--- /dev/null
+++ b/passes/cmds/exec.cc
@@ -0,0 +1,205 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 - 2020 Claire Wolf <claire@symbioticeda.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/log.h"
+#include <cstdio>
+
+#if defined(_WIN32)
+# include <csignal>
+# define WIFEXITED(x) 1
+# define WIFSIGNALED(x) 0
+# define WIFSTOPPED(x) 0
+# define WEXITSTATUS(x) ((x) & 0xff)
+# define WTERMSIG(x) SIGTERM
+# define WSTOPSIG(x) 0
+#else
+# include <sys/wait.h>
+#endif
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ExecPass : public Pass {
+ ExecPass() : Pass("exec", "execute commands in the operating system shell") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" exec [options] -- [command]\n");
+ log("\n");
+ log("Execute a command in the operating system shell. All supplied arguments are\n");
+ log("concatenated and passed as a command to popen(3). Whitespace is not guaranteed\n");
+ log("to be preserved, even if quoted. stdin and stderr are not connected, while stdout is\n");
+ log("logged unless the \"-q\" option is specified.\n");
+ log("\n");
+ log("\n");
+ log(" -q\n");
+ log(" Suppress stdout and stderr from subprocess\n");
+ log("\n");
+ log(" -expect-return <int>\n");
+ log(" Generate an error if popen() does not return specified value.\n");
+ log(" May only be specified once; the final specified value is controlling\n");
+ log(" if specified multiple times.\n");
+ log("\n");
+ log(" -expect-stdout <regex>\n");
+ log(" Generate an error if the specified regex does not match any line\n");
+ log(" in subprocess's stdout. May be specified multiple times.\n");
+ log("\n");
+ log(" -not-expect-stdout <regex>\n");
+ log(" Generate an error if the specified regex matches any line\n");
+ log(" in subprocess's stdout. May be specified multiple times.\n");
+ log("\n");
+ log("\n");
+ log(" Example: exec -q -expect-return 0 -- echo \"bananapie\" | grep \"nana\"\n");
+ log("\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ std::string cmd = "";
+ char buf[1024] = {};
+ std::string linebuf = "";
+ bool flag_cmd = false;
+ bool flag_quiet = false;
+ bool flag_expect_return = false;
+ int expect_return_value = 0;
+ bool flag_expect_stdout = false;
+ struct expect_stdout_elem {
+ bool matched;
+ bool polarity; //true: this regex must match at least one line
+ //false: this regex must not match any line
+ std::string str;
+ YS_REGEX_TYPE re;
+
+ expect_stdout_elem() : matched(false), polarity(true), str(), re(){};
+ };
+ std::vector<expect_stdout_elem> expect_stdout;
+
+ if(args.size() == 0)
+ log_cmd_error("No command provided.\n");
+
+ for(size_t argidx = 1; argidx < args.size(); ++argidx) {
+ if (flag_cmd) {
+ cmd += args[argidx] + (argidx != (args.size() - 1)? " " : "");
+ } else {
+ if (args[argidx] == "--")
+ flag_cmd = true;
+ else if (args[argidx] == "-q")
+ flag_quiet = true;
+ else if (args[argidx] == "-expect-return") {
+ flag_expect_return = true;
+ ++argidx;
+ if (argidx >= args.size())
+ log_cmd_error("No expected return value specified.\n");
+
+ expect_return_value = atoi(args[argidx].c_str());
+ } else if (args[argidx] == "-expect-stdout") {
+ flag_expect_stdout = true;
+ ++argidx;
+ if (argidx >= args.size())
+ log_cmd_error("No expected regular expression specified.\n");
+
+ try{
+ expect_stdout_elem x;
+ x.str = args[argidx];
+ x.re = YS_REGEX_COMPILE(args[argidx]);
+ expect_stdout.push_back(x);
+ } catch (const YS_REGEX_NS::regex_error& e) {
+ log_cmd_error("Error in regex expression '%s' !\n", args[argidx].c_str());
+ }
+ } else if (args[argidx] == "-not-expect-stdout") {
+ flag_expect_stdout = true;
+ ++argidx;
+ if (argidx >= args.size())
+ log_cmd_error("No expected regular expression specified.\n");
+
+ try{
+ expect_stdout_elem x;
+ x.str = args[argidx];
+ x.re = YS_REGEX_COMPILE(args[argidx]);
+ x.polarity = false;
+ expect_stdout.push_back(x);
+ } catch (const YS_REGEX_NS::regex_error& e) {
+ log_cmd_error("Error in regex expression '%s' !\n", args[argidx].c_str());
+ }
+
+ } else
+ log_cmd_error("Unknown option \"%s\" or \"--\" doesn\'t precede command.", args[argidx].c_str());
+ }
+ }
+
+ log_header(design, "Executing command \"%s\".\n", cmd.c_str());
+ log_push();
+
+ fflush(stdout);
+ bool keep_reading = true;
+ int status = 0;
+ int retval = 0;
+
+#ifndef EMSCRIPTEN
+ FILE *f = popen(cmd.c_str(), "r");
+ if (f == nullptr)
+ log_cmd_error("errno %d after popen() returned NULL.\n", errno);
+ while (keep_reading) {
+ keep_reading = (fgets(buf, sizeof(buf), f) != nullptr);
+ linebuf += buf;
+ memset(buf, 0, sizeof(buf));
+
+ auto pos = linebuf.find('\n');
+ while (pos != std::string::npos) {
+ std::string line = linebuf.substr(0, pos);
+ linebuf.erase(0, pos + 1);
+ if (!flag_quiet)
+ log("%s\n", line.c_str());
+
+ if (flag_expect_stdout)
+ for(auto &x : expect_stdout)
+ if (YS_REGEX_NS::regex_search(line, x.re))
+ x.matched = true;
+
+ pos = linebuf.find('\n');
+ }
+ }
+ status = pclose(f);
+#endif
+
+ if(WIFEXITED(status)) {
+ retval = WEXITSTATUS(status);
+ }
+ else if(WIFSIGNALED(status)) {
+ retval = WTERMSIG(status);
+ }
+ else if(WIFSTOPPED(status)) {
+ retval = WSTOPSIG(status);
+ }
+
+ if (flag_expect_return && retval != expect_return_value)
+ log_cmd_error("Return value %d did not match expected return value %d.\n", retval, expect_return_value);
+
+ if (flag_expect_stdout)
+ for (auto &x : expect_stdout)
+ if (x.polarity ^ x.matched)
+ log_cmd_error("Command stdout did%s have a line matching given regex \"%s\".\n", (x.polarity? " not" : ""), x.str.c_str());
+
+ log_pop();
+ }
+} ExecPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index 1657ef818..b64b077e4 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -625,9 +625,13 @@ static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &se
}
}
-static void select_stmt(RTLIL::Design *design, std::string arg)
+static void select_stmt(RTLIL::Design *design, std::string arg, bool disable_empty_warning = false)
{
std::string arg_mod, arg_memb;
+ std::unordered_map<std::string, bool> arg_mod_found;
+ std::unordered_map<std::string, bool> arg_memb_found;
+ auto isalpha = [](const char &x) { return ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z')); };
+ bool prefixed = GetSize(arg) >= 2 && isalpha(arg[0]) && arg[1] == ':';
if (arg.size() == 0)
return;
@@ -758,19 +762,21 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
if (!design->selected_active_module.empty()) {
arg_mod = design->selected_active_module;
arg_memb = arg;
+ if (!prefixed) arg_memb_found[arg_memb] = false;
} else
- if (GetSize(arg) >= 2 && arg[0] >= 'a' && arg[0] <= 'z' && arg[1] == ':') {
+ if (prefixed && arg[0] >= 'a' && arg[0] <= 'z') {
arg_mod = "*", arg_memb = arg;
} else {
size_t pos = arg.find('/');
if (pos == std::string::npos) {
- if (arg.find(':') == std::string::npos || arg.compare(0, 1, "A") == 0)
- arg_mod = arg;
- else
- arg_mod = "*", arg_memb = arg;
+ arg_mod = arg;
+ if (!prefixed) arg_mod_found[arg_mod] = false;
} else {
arg_mod = arg.substr(0, pos);
+ if (!prefixed) arg_mod_found[arg_mod] = false;
arg_memb = arg.substr(pos+1);
+ bool arg_memb_prefixed = GetSize(arg_memb) >= 2 && isalpha(arg_memb[0]) && arg_memb[1] == ':';
+ if (!arg_memb_prefixed) arg_memb_found[arg_memb] = false;
}
}
@@ -789,8 +795,14 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
if (!match_attr(mod->attributes, arg_mod.substr(2)))
continue;
} else
+ if (arg_mod.compare(0, 2, "N:") == 0) {
+ if (!match_ids(mod->name, arg_mod.substr(2)))
+ continue;
+ } else
if (!match_ids(mod->name, arg_mod))
continue;
+ else
+ arg_mod_found[arg_mod] = true;
if (arg_memb == "") {
sel.selected_modules.insert(mod->name);
@@ -839,7 +851,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
if (match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
- if (arg_memb.compare(0, 2, "c:") ==0) {
+ if (arg_memb.compare(0, 2, "c:") == 0) {
for (auto cell : mod->cells())
if (match_ids(cell->name, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(cell->name);
@@ -873,24 +885,44 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
if (match_attr(cell->parameters, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(cell->name);
} else {
+ std::string orig_arg_memb = arg_memb;
if (arg_memb.compare(0, 2, "n:") == 0)
arg_memb = arg_memb.substr(2);
for (auto wire : mod->wires())
- if (match_ids(wire->name, arg_memb))
+ if (match_ids(wire->name, arg_memb)) {
sel.selected_members[mod->name].insert(wire->name);
+ arg_memb_found[orig_arg_memb] = true;
+ }
for (auto &it : mod->memories)
- if (match_ids(it.first, arg_memb))
+ if (match_ids(it.first, arg_memb)) {
sel.selected_members[mod->name].insert(it.first);
+ arg_memb_found[orig_arg_memb] = true;
+ }
for (auto cell : mod->cells())
- if (match_ids(cell->name, arg_memb))
+ if (match_ids(cell->name, arg_memb)) {
sel.selected_members[mod->name].insert(cell->name);
+ arg_memb_found[orig_arg_memb] = true;
+ }
for (auto &it : mod->processes)
- if (match_ids(it.first, arg_memb))
+ if (match_ids(it.first, arg_memb)) {
sel.selected_members[mod->name].insert(it.first);
+ arg_memb_found[orig_arg_memb] = true;
+ }
}
}
select_filter_active_mod(design, work_stack.back());
+
+ for (auto &it : arg_mod_found) {
+ if (it.second == false && !disable_empty_warning) {
+ log_warning("Selection \"%s\" did not match any module.\n", it.first.c_str());
+ }
+ }
+ for (auto &it : arg_memb_found) {
+ if (it.second == false && !disable_empty_warning) {
+ log_warning("Selection \"%s\" did not match any object.\n", it.first.c_str());
+ }
+ }
}
static std::string describe_selection_for_assert(RTLIL::Design *design, RTLIL::Selection *sel)
@@ -1074,6 +1106,10 @@ struct SelectPass : public Pass {
log(" all modules with an attribute matching the given pattern\n");
log(" in addition to = also <, <=, >=, and > are supported\n");
log("\n");
+ log(" N:<pattern>\n");
+ log(" all modules with a name matching the given pattern\n");
+ log(" (i.e. 'N:' is optional as it is the default matching rule)\n");
+ log("\n");
log("An <obj_pattern> can be an object name, wildcard expression, or one of\n");
log("the following:\n");
log("\n");
@@ -1276,7 +1312,8 @@ struct SelectPass : public Pass {
}
if (arg.size() > 0 && arg[0] == '-')
log_cmd_error("Unknown option %s.\n", arg.c_str());
- select_stmt(design, arg);
+ bool disable_empty_warning = count_mode || assert_none || assert_any || (assert_count != -1) || (assert_max != -1) || (assert_min != -1);
+ select_stmt(design, arg, disable_empty_warning);
sel_str += " " + arg;
}