summaryrefslogtreecommitdiff
path: root/passes/hierarchy
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2013-01-05 11:13:26 +0100
committerClifford Wolf <clifford@clifford.at>2013-01-05 11:13:26 +0100
commit7764d0ba1dcf064ae487ee985c43083a0909e7f4 (patch)
tree18c05b8729df381af71b707748ce1d605e0df764 /passes/hierarchy
initial import
Diffstat (limited to 'passes/hierarchy')
-rw-r--r--passes/hierarchy/Makefile.inc3
-rw-r--r--passes/hierarchy/hierarchy.cc194
2 files changed, 197 insertions, 0 deletions
diff --git a/passes/hierarchy/Makefile.inc b/passes/hierarchy/Makefile.inc
new file mode 100644
index 00000000..37cc287a
--- /dev/null
+++ b/passes/hierarchy/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += passes/hierarchy/hierarchy.o
+
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
new file mode 100644
index 00000000..c8cd77a1
--- /dev/null
+++ b/passes/hierarchy/hierarchy.cc
@@ -0,0 +1,194 @@
+/*
+ * 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/register.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <set>
+
+static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check)
+{
+ bool did_something = false;
+
+ for (auto &cell_it : module->cells) {
+ RTLIL::Cell *cell = cell_it.second;
+ if (design->modules.count(cell->type) == 0) {
+ if (flag_check && cell->type[0] != '$')
+ log_error("Module `%s' referenced in module `%s' in cell `%s' is not part of the design.\n",
+ cell->type.c_str(), module->name.c_str(), cell->name.c_str());
+ continue;
+ }
+ if (cell->parameters.size() == 0)
+ continue;
+ RTLIL::Module *mod = design->modules[cell->type];
+ cell->type = mod->derive(design, cell->parameters);
+ cell->parameters.clear();
+ }
+
+ if (did_something)
+ return did_something;
+
+ std::map<RTLIL::SigSpec, int> auto_wires;
+
+ for (auto &wire_it : module->wires) {
+ if (wire_it.second->auto_width)
+ auto_wires[RTLIL::SigSpec(wire_it.second)] = -1;
+ }
+
+ for (auto &cell_it : module->cells)
+ for (auto &conn : cell_it.second->connections)
+ for (auto &awit : auto_wires) {
+ if (awit.second >= 0 || conn.second != awit.first)
+ continue;
+ if (design->modules.count(cell_it.second->type) == 0) {
+ log("WARNING: Module `%s' used in auto-delaration of the wire `%s.%s' cannot be found.\n",
+ cell_it.second->type.c_str(), module->name.c_str(), log_signal(awit.first));
+ continue;
+ }
+ RTLIL::Module *mod = design->modules[cell_it.second->type];
+ RTLIL::Wire *wire = NULL;
+ if (mod->wires.count(conn.first) == 0) {
+ for (auto &wire_it : mod->wires) {
+ if (wire_it.second->port_id == 0)
+ continue;
+ char buffer[100];
+ snprintf(buffer, 100, "$%d", wire_it.second->port_id);
+ if (buffer == conn.first) {
+ wire = wire_it.second;
+ break;
+ }
+ }
+ } else
+ wire = mod->wires[conn.first];
+ if (!wire || wire->port_id == 0)
+ log_error("No port `%s' found in `%s' but used by instanciation in `%s'!\n",
+ conn.first.c_str(), mod->name.c_str(), module->name.c_str());
+ if (wire->auto_width)
+ log_error("Signal `%s' found in `%s' and used by instanciation in `%s' for an auto wire is an auto-wire itself!\n",
+ log_signal(awit.first), mod->name.c_str(), module->name.c_str());
+ awit.second = wire->width;
+ }
+
+ std::map<RTLIL::IdString, int> auto_sizes;
+ for (auto &awit : auto_wires) {
+ if (awit.second < 0)
+ log("Can't further resolve auto-wire `%s.%s' (width %d) using cell ports.\n",
+ module->name.c_str(), awit.first.chunks[0].wire->name.c_str(),
+ awit.first.chunks[0].wire->width);
+ else
+ auto_sizes[awit.first.chunks[0].wire->name] = awit.second;
+ }
+
+ if (auto_sizes.size() > 0) {
+ module->update_auto_wires(auto_sizes);
+ log_header("Continuing EXPAND pass.\n");
+ did_something = true;
+ }
+
+ return did_something;
+}
+
+static void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, bool is_top = false)
+{
+ if (used.count(mod) > 0)
+ return;
+
+ log("%s module: %s\n", is_top ? "Top" : "Used", 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]);
+ }
+}
+
+static void hierarchy(RTLIL::Design *design, RTLIL::Module *top)
+{
+ std::set<RTLIL::Module*> used;
+ hierarchy_worker(design, used, top, true);
+
+ std::vector<RTLIL::Module*> del_modules;
+ for (auto &it : design->modules)
+ if (used.count(it.second) == 0)
+ del_modules.push_back(it.second);
+
+ for (auto mod : del_modules) {
+ log("Removing unused module `%s'.\n", mod->name.c_str());
+ design->modules.erase(mod->name);
+ delete mod;
+ }
+
+ log("Removed %zd unused modules.\n", del_modules.size());
+}
+
+struct HierarchyPass : public Pass {
+ HierarchyPass() : Pass("hierarchy") { }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing HIERARCHY pass (removing modules outside design hierarchy).\n");
+
+ bool flag_check = false;
+ RTLIL::Module *top_mod = NULL;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-check") {
+ flag_check = true;
+ continue;
+ }
+ if (args[argidx] == "-top") {
+ if (++argidx >= args.size())
+ log_cmd_error("Option -top requires an additional argument!\n");
+ if (args[argidx][0] != '$' && args[argidx][0] != '\\')
+ top_mod = design->modules.count("\\" + args[argidx]) > 0 ? design->modules["\\" + args[argidx]] : NULL;
+ else
+ top_mod = design->modules.count(args[argidx]) > 0 ? design->modules[args[argidx]] : NULL;
+ if (top_mod == NULL)
+ log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (top_mod != NULL)
+ hierarchy(design, top_mod);
+
+ bool did_something = true;
+ while (did_something) {
+ did_something = false;
+ std::vector<std::string> 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))
+ did_something = true;
+ }
+ }
+
+ if (top_mod != NULL)
+ hierarchy(design, top_mod);
+ }
+} HierarchyPass;
+