aboutsummaryrefslogtreecommitdiffstats
path: root/passes/hierarchy
diff options
context:
space:
mode:
Diffstat (limited to 'passes/hierarchy')
-rw-r--r--passes/hierarchy/Makefile.inc1
-rw-r--r--passes/hierarchy/hierarchy.cc103
-rw-r--r--passes/hierarchy/singleton.cc101
-rw-r--r--passes/hierarchy/submod.cc53
4 files changed, 203 insertions, 55 deletions
diff --git a/passes/hierarchy/Makefile.inc b/passes/hierarchy/Makefile.inc
index 99aa1e116..1fb669c11 100644
--- a/passes/hierarchy/Makefile.inc
+++ b/passes/hierarchy/Makefile.inc
@@ -1,4 +1,5 @@
OBJS += passes/hierarchy/hierarchy.o
+OBJS += passes/hierarchy/singleton.o
OBJS += passes/hierarchy/submod.o
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 58b796a62..94b93de5d 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* 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
@@ -66,7 +66,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
for (auto &conn : i2.second->connections()) {
if (conn.first[0] != '$')
portnames.insert(conn.first);
- portwidths[conn.first] = std::max(portwidths[conn.first], conn.second.size());
+ portwidths[conn.first] = max(portwidths[conn.first], conn.second.size());
}
for (auto &para : i2.second->parameters)
parameters.insert(para.first);
@@ -84,8 +84,8 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
for (auto &decl : portdecls)
if (decl.index > 0) {
- portwidths[decl.portname] = std::max(portwidths[decl.portname], 1);
- portwidths[decl.portname] = std::max(portwidths[decl.portname], portwidths[stringf("$%d", decl.index)]);
+ portwidths[decl.portname] = max(portwidths[decl.portname], 1);
+ portwidths[decl.portname] = max(portwidths[decl.portname], portwidths[stringf("$%d", decl.index)]);
log(" port %d: %s [%d:0] %s\n", decl.index, decl.input ? decl.output ? "inout" : "input" : "output", portwidths[decl.portname]-1, RTLIL::id2cstr(decl.portname));
if (indices.count(decl.index) > ports.size())
log_error("Port index (%d) exceeds number of found ports (%d).\n", decl.index, int(ports.size()));
@@ -106,7 +106,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
log_assert(!indices.empty());
indices.erase(d.index);
ports[d.index-1] = d;
- portwidths[d.portname] = std::max(portwidths[d.portname], 1);
+ portwidths[d.portname] = max(portwidths[d.portname], 1);
log(" port %d: %s [%d:0] %s\n", d.index, d.input ? d.output ? "inout" : "input" : "output", portwidths[d.portname]-1, RTLIL::id2cstr(d.portname));
goto found_matching_decl;
}
@@ -261,14 +261,14 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
return did_something;
}
-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*, IdString::compare_ptr_by_name<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);
@@ -285,9 +285,9 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTL
}
}
-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;
+ std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used;
hierarchy_worker(design, used, top, 0);
std::vector<RTLIL::Module*> del_modules;
@@ -295,17 +295,17 @@ void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib, bool f
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")
- 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 %d unused modules.\n", GetSize(del_modules));
+ log("Removed %d unused modules.\n", del_counter);
}
bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
@@ -313,12 +313,23 @@ 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")
+ if ((m != nullptr && set_keep_assert(cache, m)) || c->type.in("$assert", "$assume"))
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] = max(db[module], find_top_mod_score(design, design->module(cell->type), db) + 1);
+ }
+ return db.at(module);
+}
+
struct HierarchyPass : public Pass {
HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
virtual void help()
@@ -339,7 +350,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");
@@ -363,6 +374,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");
@@ -372,7 +386,7 @@ struct HierarchyPass : public Pass {
log("\n");
log("Input ports are specified with the 'i' prefix, output ports with the 'o'\n");
log("prefix and inout ports with the 'io' prefix. The optional <num> specifies\n");
- log("the position of the port in the parameter list (needed when instanciated\n");
+ log("the position of the port in the parameter list (needed when instantiated\n");
log("using positional arguments). When <num> is not specified, the <portname> can\n");
log("also contain wildcard characters.\n");
log("\n");
@@ -382,13 +396,14 @@ struct HierarchyPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing HIERARCHY pass (managing design hierarchy).\n");
+ log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n");
bool flag_check = false;
bool purge_lib = false;
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;
@@ -470,6 +485,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);
@@ -481,35 +500,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(design, "Finding top of design hierarchy..\n");
+ dict<Module*, int> db;
+ for (Module *mod : design->selected_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*, IdString::compare_ptr_by_name<Module>> used_modules;
+ if (top_mod != NULL) {
+ log_header(design, "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(design, "Analyzing design hierarchy..\n");
+ hierarchy_clean(design, top_mod, purge_lib);
}
if (top_mod != NULL) {
@@ -580,5 +611,5 @@ struct HierarchyPass : public Pass {
log_pop();
}
} HierarchyPass;
-
+
PRIVATE_NAMESPACE_END
diff --git a/passes/hierarchy/singleton.cc b/passes/hierarchy/singleton.cc
new file mode 100644
index 000000000..03c365fb5
--- /dev/null
+++ b/passes/hierarchy/singleton.cc
@@ -0,0 +1,101 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SingletonPass : public Pass {
+ SingletonPass() : Pass("singleton", "create singleton modules") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" singleton [selection]\n");
+ log("\n");
+ log("By default, a module that is instantiated by several other modules is only\n");
+ log("kept once in the design. This preserves the original modularity of the design\n");
+ log("and reduces the overall size of the design in memory. But it prevents certain\n");
+ log("optimizations and other operations on the design. This pass creates singleton\n");
+ log("modules for all selected cells. The created modules are marked with the\n");
+ log("'singleton' attribute.\n");
+ log("\n");
+ log("This commands only operates on modules that by themself have the 'singleton'\n");
+ log("attribute set (the 'top' module is a singleton implicitly).\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing SINGLETON pass (creating singleton modules).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-check") {
+ // flag_check = true;
+ // continue;
+ // }
+ }
+ extra_args(args, argidx, design);
+
+ bool did_something = true;
+ int singleton_cnt = 0;
+
+ while (did_something)
+ {
+ did_something = false;
+
+ for (auto module : design->selected_modules())
+ {
+ if (!module->get_bool_attribute("\\singleton") && !module->get_bool_attribute("\\top"))
+ continue;
+
+ for (auto cell : module->selected_cells())
+ {
+ auto tmod = design->module(cell->type);
+
+ if (tmod == nullptr)
+ continue;
+
+ if (tmod->get_bool_attribute("\\blackbox"))
+ continue;
+
+ if (tmod->get_bool_attribute("\\singleton"))
+ continue;
+
+ cell->type = module->name.str() + "." + log_id(cell->name);
+ log("Creating singleton '%s'.\n", log_id(cell->type));
+
+ auto smod = tmod->clone();
+ smod->name = cell->type;
+ smod->set_bool_attribute("\\singleton");
+ design->add(smod);
+
+ did_something = true;
+ singleton_cnt++;
+ }
+ }
+ }
+
+ log("Created %d singleton modules.\n", singleton_cnt);
+ }
+} SingletonPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index 8d4012c53..9f312f82d 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* 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
@@ -32,6 +32,8 @@ struct SubmodWorker
CellTypes ct;
RTLIL::Design *design;
RTLIL::Module *module;
+
+ bool copy_mode;
std::string opt_name;
struct SubModule
@@ -177,21 +179,25 @@ struct SubmodWorker
bit.wire = wire_flags[bit.wire].new_wire;
}
log(" cell %s (%s)\n", new_cell->name.c_str(), new_cell->type.c_str());
- module->remove(cell);
+ if (!copy_mode)
+ module->remove(cell);
}
submod.cells.clear();
- RTLIL::Cell *new_cell = module->addCell(submod.full_name, submod.full_name);
- for (auto &it : wire_flags)
- {
- RTLIL::Wire *old_wire = it.first;
- RTLIL::Wire *new_wire = it.second.new_wire;
- if (new_wire->port_id > 0)
- new_cell->setPort(new_wire->name, RTLIL::SigSpec(old_wire));
+ if (!copy_mode) {
+ RTLIL::Cell *new_cell = module->addCell(submod.full_name, submod.full_name);
+ for (auto &it : wire_flags)
+ {
+ RTLIL::Wire *old_wire = it.first;
+ RTLIL::Wire *new_wire = it.second.new_wire;
+ if (new_wire->port_id > 0)
+ new_cell->setPort(new_wire->name, RTLIL::SigSpec(old_wire));
+ }
}
}
- SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, std::string opt_name = std::string()) : design(design), module(module), opt_name(opt_name)
+ SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, bool copy_mode = false, std::string opt_name = std::string()) :
+ design(design), module(module), copy_mode(copy_mode), opt_name(opt_name)
{
if (!design->selected_whole_module(module->name) && opt_name.empty())
return;
@@ -266,7 +272,7 @@ struct SubmodPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" submod [selection]\n");
+ log(" submod [-copy] [selection]\n");
log("\n");
log("This pass identifies all cells with the 'submod' attribute and moves them to\n");
log("a newly created module. The value of the attribute is used as name for the\n");
@@ -279,19 +285,24 @@ struct SubmodPass : public Pass {
log("or memories.\n");
log("\n");
log("\n");
- log(" submod -name <name> [selection]\n");
+ log(" submod -name <name> [-copy] [selection]\n");
log("\n");
log("As above, but don't use the 'submod' attribute but instead use the selection.\n");
log("Only objects from one module might be selected. The value of the -name option\n");
log("is used as the value of the 'submod' attribute above.\n");
log("\n");
+ log("By default the cells are 'moved' from the source module and the source module\n");
+ log("will use an instance of the new module after this command is finished. Call\n");
+ log("with -copy to not modify the source module.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing SUBMOD pass (moving cells to submodules as requested).\n");
+ log_header(design, "Executing SUBMOD pass (moving cells to submodules as requested).\n");
log_push();
std::string opt_name;
+ bool copy_mode = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -299,6 +310,10 @@ struct SubmodPass : public Pass {
opt_name = args[++argidx];
continue;
}
+ if (args[argidx] == "-copy") {
+ copy_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -306,7 +321,7 @@ struct SubmodPass : public Pass {
if (opt_name.empty())
{
Pass::call(design, "opt_clean");
- log_header("Continuing SUBMOD pass.\n");
+ log_header(design, "Continuing SUBMOD pass.\n");
std::set<RTLIL::IdString> handled_modules;
@@ -319,7 +334,7 @@ struct SubmodPass : public Pass {
queued_modules.push_back(mod_it.first);
for (auto &modname : queued_modules)
if (design->modules_.count(modname) != 0) {
- SubmodWorker worker(design, design->modules_[modname]);
+ SubmodWorker worker(design, design->modules_[modname], copy_mode);
handled_modules.insert(modname);
did_something = true;
}
@@ -341,13 +356,13 @@ struct SubmodPass : public Pass {
log("Nothing selected -> do nothing.\n");
else {
Pass::call_on_module(design, module, "opt_clean");
- log_header("Continuing SUBMOD pass.\n");
- SubmodWorker worker(design, module, opt_name);
+ log_header(design, "Continuing SUBMOD pass.\n");
+ SubmodWorker worker(design, module, copy_mode, opt_name);
}
}
log_pop();
}
} SubmodPass;
-
+
PRIVATE_NAMESPACE_END