/* * 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;