From 7764d0ba1dcf064ae487ee985c43083a0909e7f4 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 5 Jan 2013 11:13:26 +0100 Subject: initial import --- passes/hierarchy/hierarchy.cc | 194 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 passes/hierarchy/hierarchy.cc (limited to 'passes/hierarchy/hierarchy.cc') 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 + * + * 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 +#include +#include + +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 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 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 &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 used; + hierarchy_worker(design, used, top, true); + + std::vector 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 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 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; + -- cgit v1.2.3