diff options
Diffstat (limited to 'passes/hierarchy/hierarchy.cc')
-rw-r--r-- | passes/hierarchy/hierarchy.cc | 164 |
1 files changed, 137 insertions, 27 deletions
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index e21a7a4e..5df69848 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "frontends/verific/verific.h" #include <stdlib.h> #include <stdio.h> #include <set> @@ -138,7 +139,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, } } -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, bool flag_simcheck, std::vector<std::string> &libdirs) { bool did_something = false; std::map<RTLIL::Cell*, std::pair<int, int>> array_cells; @@ -173,24 +174,24 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check for (auto &dir : libdirs) { - filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v"; - if (check_file_exists(filename)) { - std::vector<std::string> args; - args.push_back(filename); - Frontend::frontend_call(design, NULL, filename, "verilog"); - goto loaded_module; - } - - filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il"; - if (check_file_exists(filename)) { - std::vector<std::string> args; - args.push_back(filename); - Frontend::frontend_call(design, NULL, filename, "ilang"); - goto loaded_module; + static const vector<pair<string, string>> extensions_list = + { + {".v", "verilog"}, + {".sv", "verilog -sv"}, + {".il", "ilang"} + }; + + for (auto &ext : extensions_list) + { + filename = dir + "/" + RTLIL::unescape_id(cell->type) + ext.first; + if (check_file_exists(filename)) { + Frontend::frontend_call(design, NULL, filename, ext.second); + goto loaded_module; + } } } - if (flag_check && cell->type[0] != '$') + if ((flag_check || flag_simcheck) && 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; @@ -200,7 +201,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check 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) + if (flag_check || flag_simcheck) { RTLIL::Module *mod = design->module(cell->type); for (auto &conn : cell->connections()) @@ -213,15 +214,19 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check 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)); for (auto ¶m : cell->parameters) - if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$') + if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$' && strchr(param.first.c_str(), '.') == NULL) log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n", log_id(cell->type), log_id(module), log_id(cell), log_id(param.first)); } - if (cell->parameters.size() == 0) + if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) { + if (flag_simcheck) + log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n", + cell->type.c_str(), module->name.c_str(), cell->name.c_str()); continue; + } - if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) + if (cell->parameters.size() == 0) continue; RTLIL::Module *mod = design->modules_[cell->type]; @@ -254,7 +259,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check if (mod->wires_.count(portname) == 0) log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first)); int port_size = mod->wires_.at(portname)->width; - if (conn_size == port_size) + if (conn_size == port_size || conn_size == 0) continue; if (conn_size != port_size*num) log_error("Array cell `%s.%s' has invalid port vs. signal size for port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first)); @@ -317,7 +322,7 @@ 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.in("$assert", "$assume")) + if ((m != nullptr && set_keep_assert(cache, m)) || c->type.in("$assert", "$assume", "$live", "$fair", "$cover")) return cache[mod] = true; } return cache[mod]; @@ -338,7 +343,7 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db) struct HierarchyPass : public Pass { HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -354,6 +359,10 @@ struct HierarchyPass : public Pass { log(" also check the design hierarchy. this generates an error when\n"); log(" an unknown module is used as cell type.\n"); log("\n"); + log(" -simcheck\n"); + log(" like -check, but also thow an error if blackbox modules are\n"); + log(" instantiated, and throw an error if the design has no top module\n"); + log("\n"); log(" -purge_lib\n"); log(" by default the hierarchy command will not remove library (blackbox)\n"); log(" modules. use this option to also remove unused blackbox modules.\n"); @@ -367,6 +376,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(" -keep_portwidths\n"); + log(" per default this pass adjusts the port width on cells that are\n"); + log(" module instances when the width does not match the module port. this\n"); + log(" 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"); @@ -400,18 +414,21 @@ struct HierarchyPass : public Pass { log("in the current design.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n"); bool flag_check = false; + bool flag_simcheck = false; bool purge_lib = false; RTLIL::Module *top_mod = NULL; + std::string load_top_mod; std::vector<std::string> libdirs; bool auto_top_mode = false; bool generate_mode = false; bool keep_positionals = false; + bool keep_portwidths = false; bool nokeep_asserts = false; std::vector<std::string> generate_cells; std::vector<generate_port_decl_t> generate_ports; @@ -419,7 +436,7 @@ struct HierarchyPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-generate" && !flag_check && !top_mod) { + if (args[argidx] == "-generate" && !flag_check && !flag_simcheck && !top_mod) { generate_mode = true; log("Entering generate mode.\n"); while (++argidx < args.size()) { @@ -462,6 +479,10 @@ struct HierarchyPass : public Pass { flag_check = true; continue; } + if (args[argidx] == "-simcheck") { + flag_simcheck = true; + continue; + } if (args[argidx] == "-purge_lib") { purge_lib = true; continue; @@ -470,6 +491,10 @@ struct HierarchyPass : public Pass { keep_positionals = true; continue; } + if (args[argidx] == "-keep_portwidths") { + keep_portwidths = true; + continue; + } if (args[argidx] == "-nokeep_asserts") { nokeep_asserts = true; continue; @@ -488,7 +513,7 @@ struct HierarchyPass : public Pass { top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL; } if (top_mod == NULL) - log_cmd_error("Module `%s' not found!\n", args[argidx].c_str()); + load_top_mod = args[argidx]; continue; } if (args[argidx] == "-auto-top") { @@ -499,6 +524,22 @@ struct HierarchyPass : public Pass { } extra_args(args, argidx, design, false); + if (!load_top_mod.empty()) { +#ifdef YOSYS_ENABLE_VERIFIC + if (verific_import_pending) { + verific_import(design, load_top_mod); + top_mod = design->module(RTLIL::escape_id(load_top_mod)); + } +#endif + if (top_mod == NULL) + log_cmd_error("Module `%s' not found!\n", load_top_mod.c_str()); + } else { +#ifdef YOSYS_ENABLE_VERIFIC + if (verific_import_pending) + verific_import(design); +#endif + } + if (generate_mode) { generate(design, generate_cells, generate_ports); return; @@ -524,6 +565,9 @@ struct HierarchyPass : public Pass { log("Automatically selected %s as design top module.\n", log_id(top_mod)); } + if (flag_simcheck && top_mod == nullptr) + log_error("Design has no top module.\n"); + bool did_something = true; while (did_something) { @@ -539,7 +583,7 @@ struct HierarchyPass : public Pass { } for (auto module : used_modules) { - if (expand_module(design, module, flag_check, libdirs)) + if (expand_module(design, module, flag_check, flag_simcheck, libdirs)) did_something = true; } } @@ -614,6 +658,72 @@ struct HierarchyPass : public Pass { } } + std::set<Module*> blackbox_derivatives; + std::vector<Module*> design_modules = design->modules(); + + for (auto module : design_modules) + for (auto cell : module->cells()) + { + Module *m = design->module(cell->type); + + if (m == nullptr) + continue; + + if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty()) { + IdString new_m_name = m->derive(design, cell->parameters, true); + if (new_m_name.empty()) + continue; + if (new_m_name != m->name) { + m = design->module(new_m_name); + blackbox_derivatives.insert(m); + } + } + + for (auto &conn : cell->connections()) + { + Wire *w = m->wire(conn.first); + + if (w == nullptr || w->port_id == 0) + continue; + + if (GetSize(conn.second) == 0) + continue; + + SigSpec sig = conn.second; + + if (!keep_portwidths && GetSize(w) != GetSize(conn.second)) + { + if (GetSize(w) < GetSize(conn.second)) + { + int n = GetSize(conn.second) - GetSize(w); + if (!w->port_input && w->port_output) + module->connect(sig.extract(GetSize(w), n), Const(0, n)); + sig.remove(GetSize(w), n); + } + else + { + int n = GetSize(w) - GetSize(conn.second); + if (w->port_input && !w->port_output) + sig.append(Const(0, n)); + else + sig.append(module->addWire(NEW_ID, n)); + } + + if (!conn.second.is_fully_const() || !w->port_input || w->port_output) + log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell), + log_id(conn.first), GetSize(conn.second), GetSize(sig)); + cell->setPort(conn.first, sig); + } + + if (w->port_output && !w->port_input && sig.has_const()) + log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n", + log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig)); + } + } + + for (auto module : blackbox_derivatives) + design->remove(module); + log_pop(); } } HierarchyPass; |