39 void generate(
RTLIL::Design *design,
const std::vector<std::string> &celltypes,
const std::vector<generate_port_decl_t> &portdecls)
41 std::set<RTLIL::IdString> found_celltypes;
44 for (
auto i2 : i1.second->cells_)
51 for (
auto &pattern : celltypes)
53 found_celltypes.insert(cell->
type);
56 for (
auto &celltype : found_celltypes)
58 std::set<RTLIL::IdString> portnames;
59 std::set<RTLIL::IdString> parameters;
60 std::map<RTLIL::IdString, int> portwidths;
61 log(
"Generate module for cell type %s:\n", celltype.c_str());
64 for (
auto i2 : i1.second->cells_)
65 if (i2.second->type == celltype) {
66 for (
auto &conn : i2.second->connections()) {
67 if (conn.first[0] !=
'$')
68 portnames.insert(conn.first);
69 portwidths[conn.first] = std::max(portwidths[conn.first], conn.second.size());
71 for (
auto ¶ : i2.second->parameters)
72 parameters.insert(para.first);
75 for (
auto &decl : portdecls)
77 portnames.insert(decl.portname);
79 std::set<int> indices;
80 for (
int i = 0; i < int(portnames.size()); i++)
83 std::vector<generate_port_decl_t> ports(portnames.size());
85 for (
auto &decl : portdecls)
87 portwidths[decl.portname] = std::max(portwidths[decl.portname], 1);
88 portwidths[decl.portname] = std::max(portwidths[decl.portname], portwidths[
stringf(
"$%d", decl.index)]);
89 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));
90 if (indices.count(decl.index) > ports.size())
91 log_error(
"Port index (%d) exceeds number of found ports (%d).\n", decl.index,
int(ports.size()));
92 if (indices.count(decl.index) == 0)
93 log_error(
"Conflict on port index %d.\n", decl.index);
94 indices.erase(decl.index);
95 portnames.erase(decl.portname);
96 ports[decl.index-1] = decl;
99 while (portnames.size() > 0) {
101 for (
auto &decl : portdecls)
105 d.
index = *indices.begin();
107 indices.erase(d.
index);
108 ports[d.
index-1] = d;
111 goto found_matching_decl;
114 found_matching_decl:;
115 portnames.erase(portname);
121 mod->
name = celltype;
125 for (
auto &decl : ports) {
126 RTLIL::Wire *wire = mod->addWire(decl.portname, portwidths.at(decl.portname));
134 for (
auto ¶ : parameters)
144 std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
145 std::string filename;
147 for (
auto &cell_it : module->
cells_)
152 int pos_idx = cell->
type.
str().find_first_of(
':');
153 int pos_num = cell->
type.
str().find_first_of(
':', pos_idx + 1);
154 int pos_type = cell->
type.
str().find_first_of(
':', pos_num + 1);
155 int idx = atoi(cell->
type.
str().substr(pos_idx + 1, pos_num).c_str());
156 int num = atoi(cell->
type.
str().substr(pos_num + 1, pos_type).c_str());
157 array_cells[cell] = std::pair<int, int>(
idx, num);
158 cell->
type = cell->
type.
str().substr(pos_type + 1);
167 did_something =
true;
171 if (cell->
type[0] ==
'$')
174 for (
auto &dir : libdirs)
178 std::vector<std::string>
args;
179 args.push_back(filename);
186 std::vector<std::string>
args;
187 args.push_back(filename);
193 if (flag_check && cell->
type[0] !=
'$')
194 log_error(
"Module `%s' referenced in module `%s' in cell `%s' is not part of the design.\n",
200 log_error(
"File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->
type.
c_str());
201 did_something =
true;
207 if (design->
modules_.at(cell->
type)->get_bool_attribute(
"\\blackbox"))
213 did_something =
true;
216 for (
auto &it : array_cells)
219 int idx = it.second.first, num = it.second.second;
227 int conn_size = conn.second.size();
229 if (portname.
substr(0, 1) ==
"$") {
230 int port_id = atoi(portname.
substr(1).c_str());
231 for (
auto &wire_it : mod->
wires_)
232 if (wire_it.second->port_id == port_id) {
233 portname = wire_it.first;
237 if (mod->
wires_.count(portname) == 0)
239 int port_size = mod->
wires_.at(portname)->width;
240 if (conn_size == port_size)
242 if (conn_size != port_size*num)
244 conn.second = conn.second.extract(port_size*idx, port_size);
253 if (used.count(mod) > 0)
259 log(
"Used module: %*s%s\n", indent,
"", mod->
name.
c_str());
262 for (
auto cell : mod->
cells()) {
263 std::string celltype = cell->type.str();
264 if (celltype.substr(0, 7) ==
"$array:") {
265 int pos_idx = celltype.find_first_of(
':');
266 int pos_num = celltype.find_first_of(
':', pos_idx + 1);
267 int pos_type = celltype.find_first_of(
':', pos_num + 1);
268 celltype = celltype.substr(pos_type + 1);
270 if (design->
module(celltype))
277 std::set<RTLIL::Module*> used;
280 std::vector<RTLIL::Module*> del_modules;
282 if (used.count(it.second) == 0)
283 del_modules.push_back(it.second);
285 for (
auto mod : del_modules) {
286 if (first_pass && mod->name.substr(0, 9) ==
"$abstract")
288 if (!purge_lib && mod->get_bool_attribute(
"\\blackbox"))
290 log(
"Removing unused module `%s'.\n", mod->name.c_str());
295 log(
"Removed %d unused modules.\n",
GetSize(del_modules));
300 if (cache.count(mod) == 0)
301 for (
auto c : mod->
cells()) {
303 if ((m !=
nullptr &&
set_keep_assert(cache, m)) || c->type ==
"$assert")
304 return cache[mod] =
true;
315 log(
" hierarchy [-check] [-top <module>]\n");
316 log(
" hierarchy -generate <cell-types> <port-decls>\n");
318 log(
"In parametric designs, a module might exists in several variations with\n");
319 log(
"different parameter values. This pass looks at all modules in the current\n");
320 log(
"design an re-runs the language frontends for the parametric modules as\n");
324 log(
" also check the design hierarchy. this generates an error when\n");
325 log(
" an unknown module is used as cell type.\n");
327 log(
" -purge_lib\n");
328 log(
" by default the hierarchy command will not remove library (blackbox)\n");
329 log(
" module. use this options to also remove unused blackbox modules.\n");
331 log(
" -libdir <directory>\n");
332 log(
" search for files named <module_name>.v in the specified directory\n");
333 log(
" for unknown modules and automatically run read_verilog for each\n");
334 log(
" unknown module.\n");
336 log(
" -keep_positionals\n");
337 log(
" per default this pass also converts positional arguments in cells\n");
338 log(
" to arguments using port names. this option disables this behavior.\n");
340 log(
" -nokeep_asserts\n");
341 log(
" per default this pass sets the \"keep\" attribute on all modules\n");
342 log(
" that directly or indirectly contain one or more $assert cells. this\n");
343 log(
" option disables this behavior.\n");
345 log(
" -top <module>\n");
346 log(
" use the specified top module to built a design hierarchy. modules\n");
347 log(
" outside this tree (unused modules) are removed.\n");
349 log(
" when the -top option is used, the 'top' attribute will be set on the\n");
350 log(
" specified top module. otherwise a module with the 'top' attribute set\n");
351 log(
" will implicitly be used as top module, if such a module exists.\n");
353 log(
"In -generate mode this pass generates blackbox modules for the given cell\n");
354 log(
"types (wildcards supported). For this the design is searched for cells that\n");
355 log(
"match the given types and then the given port declarations are used to\n");
356 log(
"determine the direction of the ports. The syntax for a port declaration is:\n");
358 log(
" {i|o|io}[@<num>]:<portname>\n");
360 log(
"Input ports are specified with the 'i' prefix, output ports with the 'o'\n");
361 log(
"prefix and inout ports with the 'io' prefix. The optional <num> specifies\n");
362 log(
"the position of the port in the parameter list (needed when instanciated\n");
363 log(
"using positional arguments). When <num> is not specified, the <portname> can\n");
364 log(
"also contain wildcard characters.\n");
366 log(
"This pass ignores the current selection and always operates on all modules\n");
367 log(
"in the current design.\n");
372 log_header(
"Executing HIERARCHY pass (managing design hierarchy).\n");
374 bool flag_check =
false;
375 bool purge_lib =
false;
377 std::vector<std::string> libdirs;
379 bool generate_mode =
false;
380 bool keep_positionals =
false;
381 bool nokeep_asserts =
false;
382 std::vector<std::string> generate_cells;
383 std::vector<generate_port_decl_t> generate_ports;
386 for (argidx = 1; argidx < args.size(); argidx++)
388 if (args[argidx] ==
"-generate" && !flag_check && !top_mod) {
389 generate_mode =
true;
390 log(
"Entering generate mode.\n");
391 while (++argidx < args.size()) {
392 const char *p = args[argidx].c_str();
394 if (p[0] ==
'i' && p[1] ==
'o')
404 decl.
index = strtol(++p, &endptr, 10);
415 log(
"Port declaration: %s", decl.
input ? decl.
output ?
"inout" :
"input" :
"output");
417 log(
" [at position %d]", decl.
index);
419 generate_ports.push_back(decl);
422 log(
"Celltype: %s\n", args[argidx].c_str());
427 if (args[argidx] ==
"-check") {
431 if (args[argidx] ==
"-purge_lib") {
435 if (args[argidx] ==
"-keep_positionals") {
436 keep_positionals =
true;
439 if (args[argidx] ==
"-nokeep_asserts") {
440 nokeep_asserts =
true;
443 if (args[argidx] ==
"-libdir" && argidx+1 < args.size()) {
444 libdirs.push_back(args[++argidx]);
447 if (args[argidx] ==
"-top") {
448 if (++argidx >= args.size())
449 log_cmd_error(
"Option -top requires an additional argument!\n");
452 std::map<RTLIL::IdString, RTLIL::Const> empty_parameters;
457 log_cmd_error(
"Module `%s' not found!\n", args[argidx].c_str());
465 generate(design, generate_cells, generate_ports);
472 for (
auto &mod_it : design->
modules_)
473 if (mod_it.second->get_bool_attribute(
"\\top"))
474 top_mod = mod_it.second;
477 hierarchy(design, top_mod, purge_lib,
true);
480 bool did_something_once =
false;
481 while (did_something) {
482 did_something =
false;
483 std::vector<RTLIL::IdString> modnames;
484 modnames.reserve(design->
modules_.size());
485 for (
auto &mod_it : design->
modules_)
486 modnames.push_back(mod_it.first);
487 for (
auto &modname : modnames) {
488 if (design->
modules_.count(modname) == 0)
491 did_something =
true;
494 did_something_once =
true;
497 if (top_mod !=
NULL && did_something_once) {
498 log_header(
"Re-running hierarchy analysis..\n");
499 hierarchy(design, top_mod, purge_lib,
false);
502 if (top_mod !=
NULL) {
503 for (
auto &mod_it : design->
modules_)
504 if (mod_it.second == top_mod)
507 mod_it.second->attributes.erase(
"\\top");
510 if (!nokeep_asserts) {
511 std::map<RTLIL::Module*, bool> cache;
512 for (
auto mod : design->
modules())
514 log(
"Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n",
log_id(mod));
515 mod->set_bool_attribute(
"\\keep");
519 if (!keep_positionals)
521 std::set<RTLIL::Module*> pos_mods;
523 std::vector<std::pair<RTLIL::Module*,RTLIL::Cell*>> pos_work;
525 for (
auto &mod_it : design->
modules_)
526 for (
auto &cell_it : mod_it.second->cells_) {
531 if (conn.first[0] ==
'$' &&
'0' <= conn.first[1] && conn.first[1] <=
'9') {
533 pos_work.push_back(std::pair<RTLIL::Module*,RTLIL::Cell*>(mod_it.second, cell));
538 for (
auto module : pos_mods)
545 for (
auto &work : pos_work) {
548 log(
"Mapping positional arguments of cell %s.%s (%s).\n",
550 std::map<RTLIL::IdString, RTLIL::SigSpec> new_connections;
552 if (conn.first[0] ==
'$' &&
'0' <= conn.first[1] && conn.first[1] <=
'9') {
553 int id = atoi(conn.first.c_str()+1);
554 std::pair<RTLIL::Module*,int> key(design->
modules_.at(cell->
type),
id);
555 if (pos_map.count(key) == 0) {
556 log(
" Failed to map positional argument %d of cell %s.%s (%s).\n",
558 new_connections[conn.first] = conn.second;
560 new_connections[pos_map.at(key)] = conn.second;
562 new_connections[conn.first] = conn.second;
const char * c_str() const
std::string stringf(const char *fmt,...)
void add(RTLIL::Module *module)
void log_header(const char *format,...)
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
std::map< RTLIL::IdString, RTLIL::Wire * > wires_
static std::string unescape_id(std::string str)
static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command)
static std::string idx(std::string str)
void log_error(const char *format,...)
std::map< RTLIL::IdString, RTLIL::Const > parameters
virtual RTLIL::IdString derive(RTLIL::Design *design, std::map< RTLIL::IdString, RTLIL::Const > parameters)
static std::string escape_id(std::string str)
void hierarchy_worker(RTLIL::Design *design, std::set< RTLIL::Module * > &used, RTLIL::Module *mod, int indent)
USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN bool did_something
bool patmatch(const char *pattern, const char *string)
#define PRIVATE_NAMESPACE_BEGIN
int GetSize(RTLIL::Wire *wire)
bool set_keep_assert(std::map< RTLIL::Module *, bool > &cache, RTLIL::Module *mod)
#define log_assert(_assert_expr_)
bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector< std::string > &libdirs)
#define PRIVATE_NAMESPACE_END
static const char * id2cstr(const RTLIL::IdString &str)
void log_cmd_error(const char *format,...)
bool check_file_exists(std::string filename, bool is_exec)
RTLIL::Module * module(RTLIL::IdString name)
std::string substr(size_t pos=0, size_t len=std::string::npos) const
bool has(RTLIL::IdString id) const
#define USING_YOSYS_NAMESPACE
RTLIL::ObjRange< RTLIL::Cell * > cells()
RTLIL::ObjRange< RTLIL::Module * > modules()
std::map< RTLIL::IdString, RTLIL::Module * > modules_
std::map< RTLIL::IdString, RTLIL::Cell * > cells_
void log(const char *format,...)
std::map< RTLIL::IdString, RTLIL::SigSpec > connections_
std::string id(RTLIL::IdString internal_id, bool may_rename=true)
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
HierarchyPass HierarchyPass
const std::map< RTLIL::IdString, RTLIL::SigSpec > & connections() const
void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib, bool first_pass)
const char * log_id(RTLIL::IdString str)
void generate(RTLIL::Design *design, const std::vector< std::string > &celltypes, const std::vector< generate_port_decl_t > &portdecls)