aboutsummaryrefslogtreecommitdiffstats
path: root/passes/hierarchy/hierarchy.cc
diff options
context:
space:
mode:
Diffstat (limited to 'passes/hierarchy/hierarchy.cc')
-rw-r--r--passes/hierarchy/hierarchy.cc183
1 files changed, 135 insertions, 48 deletions
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 14bf8d1bd..a393343d1 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -17,23 +17,26 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
#include <stdlib.h>
#include <stdio.h>
-#include <fnmatch.h>
#include <set>
-#include <unistd.h>
-
-namespace {
- struct generate_port_decl_t {
- bool input, output;
- RTLIL::IdString portname;
- int index;
- };
-}
-static void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, const std::vector<generate_port_decl_t> &portdecls)
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct generate_port_decl_t {
+ bool input, output;
+ string portname;
+ int index;
+};
+
+void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, const std::vector<generate_port_decl_t> &portdecls)
{
std::set<RTLIL::IdString> found_celltypes;
@@ -46,7 +49,7 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
if (cell->type.substr(0, 1) == "$" && cell->type.substr(0, 3) != "$__")
continue;
for (auto &pattern : celltypes)
- if (!fnmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str(), FNM_NOESCAPE))
+ if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str()))
found_celltypes.insert(cell->type);
}
@@ -96,9 +99,9 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
while (portnames.size() > 0) {
RTLIL::IdString portname = *portnames.begin();
for (auto &decl : portdecls)
- if (decl.index == 0 && !fnmatch(decl.portname.c_str(), RTLIL::unescape_id(portname).c_str(), FNM_NOESCAPE)) {
+ if (decl.index == 0 && patmatch(decl.portname.c_str(), RTLIL::unescape_id(portname).c_str())) {
generate_port_decl_t d = decl;
- d.portname = portname;
+ d.portname = portname.str();
d.index = *indices.begin();
log_assert(!indices.empty());
indices.erase(d.index);
@@ -135,7 +138,7 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
}
}
-static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
+bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
{
bool did_something = false;
std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
@@ -171,7 +174,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
for (auto &dir : libdirs)
{
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
- if (access(filename.c_str(), F_OK) == 0) {
+ if (check_file_exists(filename)) {
std::vector<std::string> args;
args.push_back(filename);
Frontend::frontend_call(design, NULL, filename, "verilog");
@@ -179,7 +182,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
}
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
- if (access(filename.c_str(), F_OK) == 0) {
+ if (check_file_exists(filename)) {
std::vector<std::string> args;
args.push_back(filename);
Frontend::frontend_call(design, NULL, filename, "ilang");
@@ -196,6 +199,19 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
if (design->modules_.count(cell->type) == 0)
log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str());
did_something = true;
+ } else
+ if (flag_check)
+ {
+ RTLIL::Module *mod = design->module(cell->type);
+ for (auto &conn : cell->connections())
+ if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
+ int id = atoi(conn.first.c_str()+1);
+ if (id <= 0 || id > GetSize(mod->ports))
+ log_error("Module `%s' referenced in module `%s' in cell `%s' has only %d ports, requested port %d.\n",
+ log_id(cell->type), log_id(module), log_id(cell), GetSize(mod->ports), id);
+ } else if (mod->wire(conn.first) == nullptr || mod->wire(conn.first)->port_id == 0)
+ log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n",
+ log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first));
}
if (cell->parameters.size() == 0)
@@ -245,24 +261,31 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
return did_something;
}
-static void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, int indent)
+void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, int indent)
{
if (used.count(mod) > 0)
return;
if (indent == 0)
log("Top module: %s\n", mod->name.c_str());
- else
+ else if (!mod->get_bool_attribute("\\blackbox"))
log("Used module: %*s%s\n", indent, "", mod->name.c_str());
used.insert(mod);
- for (auto &it : mod->cells_) {
- if (design->modules_.count(it.second->type) > 0)
- hierarchy_worker(design, used, design->modules_[it.second->type], indent+4);
+ for (auto cell : mod->cells()) {
+ std::string celltype = cell->type.str();
+ if (celltype.substr(0, 7) == "$array:") {
+ int pos_idx = celltype.find_first_of(':');
+ int pos_num = celltype.find_first_of(':', pos_idx + 1);
+ int pos_type = celltype.find_first_of(':', pos_num + 1);
+ celltype = celltype.substr(pos_type + 1);
+ }
+ if (design->module(celltype))
+ hierarchy_worker(design, used, design->module(celltype), indent+4);
}
}
-static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib, bool first_pass)
+void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
{
std::set<RTLIL::Module*> used;
hierarchy_worker(design, used, top, 0);
@@ -272,17 +295,41 @@ static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib,
if (used.count(it.second) == 0)
del_modules.push_back(it.second);
+ int del_counter = 0;
for (auto mod : del_modules) {
- if (first_pass && mod->name.substr(0, 9) == "$abstract")
+ if (mod->name.substr(0, 9) == "$abstract")
continue;
if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
continue;
log("Removing unused module `%s'.\n", mod->name.c_str());
design->modules_.erase(mod->name);
+ del_counter++;
delete mod;
}
- log("Removed %zd unused modules.\n", del_modules.size());
+ log("Removed %d unused modules.\n", del_counter);
+}
+
+bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
+{
+ if (cache.count(mod) == 0)
+ for (auto c : mod->cells()) {
+ RTLIL::Module *m = mod->design->module(c->type);
+ if ((m != nullptr && set_keep_assert(cache, m)) || c->type == "$assert")
+ return cache[mod] = true;
+ }
+ return cache[mod];
+}
+
+int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
+{
+ if (db.count(module) == 0) {
+ db[module] = 0;
+ for (auto cell : module->cells())
+ if (design->module(cell->type))
+ db[module] = std::max(db[module], find_top_mod_score(design, design->module(cell->type), db) + 1);
+ }
+ return db.at(module);
}
struct HierarchyPass : public Pass {
@@ -305,7 +352,7 @@ struct HierarchyPass : public Pass {
log("\n");
log(" -purge_lib\n");
log(" by default the hierarchy command will not remove library (blackbox)\n");
- log(" module. use this options to also remove unused blackbox modules.\n");
+ log(" modules. use this option to also remove unused blackbox modules.\n");
log("\n");
log(" -libdir <directory>\n");
log(" search for files named <module_name>.v in the specified directory\n");
@@ -316,6 +363,11 @@ struct HierarchyPass : public Pass {
log(" per default this pass also converts positional arguments in cells\n");
log(" to arguments using port names. this option disables this behavior.\n");
log("\n");
+ log(" -nokeep_asserts\n");
+ log(" per default this pass sets the \"keep\" attribute on all modules\n");
+ log(" that directly or indirectly contain one or more $assert cells. this\n");
+ log(" option disables this behavior.\n");
+ log("\n");
log(" -top <module>\n");
log(" use the specified top module to built a design hierarchy. modules\n");
log(" outside this tree (unused modules) are removed.\n");
@@ -324,6 +376,9 @@ struct HierarchyPass : public Pass {
log(" specified top module. otherwise a module with the 'top' attribute set\n");
log(" will implicitly be used as top module, if such a module exists.\n");
log("\n");
+ log(" -auto-top\n");
+ log(" automatically determine the top of the design hierarchy and mark it.\n");
+ log("\n");
log("In -generate mode this pass generates blackbox modules for the given cell\n");
log("types (wildcards supported). For this the design is searched for cells that\n");
log("match the given types and then the given port declarations are used to\n");
@@ -350,8 +405,10 @@ struct HierarchyPass : public Pass {
RTLIL::Module *top_mod = NULL;
std::vector<std::string> libdirs;
+ bool auto_top_mode = false;
bool generate_mode = false;
bool keep_positionals = false;
+ bool nokeep_asserts = false;
std::vector<std::string> generate_cells;
std::vector<generate_port_decl_t> generate_ports;
@@ -409,6 +466,10 @@ struct HierarchyPass : public Pass {
keep_positionals = true;
continue;
}
+ if (args[argidx] == "-nokeep_asserts") {
+ nokeep_asserts = true;
+ continue;
+ }
if (args[argidx] == "-libdir" && argidx+1 < args.size()) {
libdirs.push_back(args[++argidx]);
continue;
@@ -418,7 +479,7 @@ struct HierarchyPass : public Pass {
log_cmd_error("Option -top requires an additional argument!\n");
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
- std::map<RTLIL::IdString, RTLIL::Const> empty_parameters;
+ dict<RTLIL::IdString, RTLIL::Const> empty_parameters;
design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
}
@@ -426,6 +487,10 @@ struct HierarchyPass : public Pass {
log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
continue;
}
+ if (args[argidx] == "-auto-top") {
+ auto_top_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design, false);
@@ -437,35 +502,47 @@ struct HierarchyPass : public Pass {
log_push();
- if (top_mod == NULL)
+ if (top_mod == nullptr)
for (auto &mod_it : design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
top_mod = mod_it.second;
- if (top_mod != NULL)
- hierarchy(design, top_mod, purge_lib, true);
+ if (top_mod == nullptr && auto_top_mode) {
+ log_header("Finding top of design hierarchy..\n");
+ dict<Module*, int> db;
+ for (Module *mod : design->modules()) {
+ int score = find_top_mod_score(design, mod, db);
+ log("root of %3d design levels: %-20s\n", score, log_id(mod));
+ if (!top_mod || score > db[top_mod])
+ top_mod = mod;
+ }
+ if (top_mod != nullptr)
+ log("Automatically selected %s as design top module.\n", log_id(top_mod));
+ }
bool did_something = true;
- bool did_something_once = false;
- while (did_something) {
+ while (did_something)
+ {
did_something = false;
- std::vector<RTLIL::IdString> modnames;
- modnames.reserve(design->modules_.size());
- for (auto &mod_it : design->modules_)
- modnames.push_back(mod_it.first);
- for (auto &modname : modnames) {
- if (design->modules_.count(modname) == 0)
- continue;
- if (expand_module(design, design->modules_[modname], flag_check, libdirs))
+
+ std::set<RTLIL::Module*> used_modules;
+ if (top_mod != NULL) {
+ log_header("Analyzing design hierarchy..\n");
+ hierarchy_worker(design, used_modules, top_mod, 0);
+ } else {
+ for (auto mod : design->modules())
+ used_modules.insert(mod);
+ }
+
+ for (auto module : used_modules) {
+ if (expand_module(design, module, flag_check, libdirs))
did_something = true;
}
- if (did_something)
- did_something_once = true;
}
- if (top_mod != NULL && did_something_once) {
- log_header("Re-running hierarchy analysis..\n");
- hierarchy(design, top_mod, purge_lib, false);
+ if (top_mod != NULL) {
+ log_header("Analyzing design hierarchy..\n");
+ hierarchy_clean(design, top_mod, purge_lib);
}
if (top_mod != NULL) {
@@ -476,6 +553,15 @@ struct HierarchyPass : public Pass {
mod_it.second->attributes.erase("\\top");
}
+ if (!nokeep_asserts) {
+ std::map<RTLIL::Module*, bool> cache;
+ for (auto mod : design->modules())
+ if (set_keep_assert(cache, mod)) {
+ log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod));
+ mod->set_bool_attribute("\\keep");
+ }
+ }
+
if (!keep_positionals)
{
std::set<RTLIL::Module*> pos_mods;
@@ -507,7 +593,7 @@ struct HierarchyPass : public Pass {
RTLIL::Cell *cell = work.second;
log("Mapping positional arguments of cell %s.%s (%s).\n",
RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
- std::map<RTLIL::IdString, RTLIL::SigSpec> new_connections;
+ dict<RTLIL::IdString, RTLIL::SigSpec> new_connections;
for (auto &conn : cell->connections())
if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
int id = atoi(conn.first.c_str()+1);
@@ -528,3 +614,4 @@ struct HierarchyPass : public Pass {
}
} HierarchyPass;
+PRIVATE_NAMESPACE_END