Add automatic verific import in hierarchy command
[yosys.git] / passes / hierarchy / hierarchy.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/yosys.h"
21 #include "frontends/verific/verific.h"
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <set>
25
26 #ifndef _WIN32
27 # include <unistd.h>
28 #endif
29
30
31 USING_YOSYS_NAMESPACE
32 PRIVATE_NAMESPACE_BEGIN
33
34 struct generate_port_decl_t {
35 bool input, output;
36 string portname;
37 int index;
38 };
39
40 void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, const std::vector<generate_port_decl_t> &portdecls)
41 {
42 std::set<RTLIL::IdString> found_celltypes;
43
44 for (auto i1 : design->modules_)
45 for (auto i2 : i1.second->cells_)
46 {
47 RTLIL::Cell *cell = i2.second;
48 if (design->has(cell->type))
49 continue;
50 if (cell->type.substr(0, 1) == "$" && cell->type.substr(0, 3) != "$__")
51 continue;
52 for (auto &pattern : celltypes)
53 if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str()))
54 found_celltypes.insert(cell->type);
55 }
56
57 for (auto &celltype : found_celltypes)
58 {
59 std::set<RTLIL::IdString> portnames;
60 std::set<RTLIL::IdString> parameters;
61 std::map<RTLIL::IdString, int> portwidths;
62 log("Generate module for cell type %s:\n", celltype.c_str());
63
64 for (auto i1 : design->modules_)
65 for (auto i2 : i1.second->cells_)
66 if (i2.second->type == celltype) {
67 for (auto &conn : i2.second->connections()) {
68 if (conn.first[0] != '$')
69 portnames.insert(conn.first);
70 portwidths[conn.first] = max(portwidths[conn.first], conn.second.size());
71 }
72 for (auto &para : i2.second->parameters)
73 parameters.insert(para.first);
74 }
75
76 for (auto &decl : portdecls)
77 if (decl.index > 0)
78 portnames.insert(decl.portname);
79
80 std::set<int> indices;
81 for (int i = 0; i < int(portnames.size()); i++)
82 indices.insert(i+1);
83
84 std::vector<generate_port_decl_t> ports(portnames.size());
85
86 for (auto &decl : portdecls)
87 if (decl.index > 0) {
88 portwidths[decl.portname] = max(portwidths[decl.portname], 1);
89 portwidths[decl.portname] = max(portwidths[decl.portname], portwidths[stringf("$%d", decl.index)]);
90 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));
91 if (indices.count(decl.index) > ports.size())
92 log_error("Port index (%d) exceeds number of found ports (%d).\n", decl.index, int(ports.size()));
93 if (indices.count(decl.index) == 0)
94 log_error("Conflict on port index %d.\n", decl.index);
95 indices.erase(decl.index);
96 portnames.erase(decl.portname);
97 ports[decl.index-1] = decl;
98 }
99
100 while (portnames.size() > 0) {
101 RTLIL::IdString portname = *portnames.begin();
102 for (auto &decl : portdecls)
103 if (decl.index == 0 && patmatch(decl.portname.c_str(), RTLIL::unescape_id(portname).c_str())) {
104 generate_port_decl_t d = decl;
105 d.portname = portname.str();
106 d.index = *indices.begin();
107 log_assert(!indices.empty());
108 indices.erase(d.index);
109 ports[d.index-1] = d;
110 portwidths[d.portname] = max(portwidths[d.portname], 1);
111 log(" port %d: %s [%d:0] %s\n", d.index, d.input ? d.output ? "inout" : "input" : "output", portwidths[d.portname]-1, RTLIL::id2cstr(d.portname));
112 goto found_matching_decl;
113 }
114 log_error("Can't match port %s.\n", RTLIL::id2cstr(portname));
115 found_matching_decl:;
116 portnames.erase(portname);
117 }
118
119 log_assert(indices.empty());
120
121 RTLIL::Module *mod = new RTLIL::Module;
122 mod->name = celltype;
123 mod->attributes["\\blackbox"] = RTLIL::Const(1);
124 design->add(mod);
125
126 for (auto &decl : ports) {
127 RTLIL::Wire *wire = mod->addWire(decl.portname, portwidths.at(decl.portname));
128 wire->port_id = decl.index;
129 wire->port_input = decl.input;
130 wire->port_output = decl.output;
131 }
132
133 mod->fixup_ports();
134
135 for (auto &para : parameters)
136 log(" ignoring parameter %s.\n", RTLIL::id2cstr(para));
137
138 log(" module %s created.\n", RTLIL::id2cstr(mod->name));
139 }
140 }
141
142 bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs)
143 {
144 bool did_something = false;
145 std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
146 std::string filename;
147
148 for (auto &cell_it : module->cells_)
149 {
150 RTLIL::Cell *cell = cell_it.second;
151
152 if (cell->type.substr(0, 7) == "$array:") {
153 int pos_idx = cell->type.str().find_first_of(':');
154 int pos_num = cell->type.str().find_first_of(':', pos_idx + 1);
155 int pos_type = cell->type.str().find_first_of(':', pos_num + 1);
156 int idx = atoi(cell->type.str().substr(pos_idx + 1, pos_num).c_str());
157 int num = atoi(cell->type.str().substr(pos_num + 1, pos_type).c_str());
158 array_cells[cell] = std::pair<int, int>(idx, num);
159 cell->type = cell->type.str().substr(pos_type + 1);
160 }
161
162 if (design->modules_.count(cell->type) == 0)
163 {
164 if (design->modules_.count("$abstract" + cell->type.str()))
165 {
166 cell->type = design->modules_.at("$abstract" + cell->type.str())->derive(design, cell->parameters);
167 cell->parameters.clear();
168 did_something = true;
169 continue;
170 }
171
172 if (cell->type[0] == '$')
173 continue;
174
175 for (auto &dir : libdirs)
176 {
177 static const vector<pair<string, string>> extensions_list =
178 {
179 {".v", "verilog"},
180 {".sv", "verilog -sv"},
181 {".il", "ilang"}
182 };
183
184 for (auto &ext : extensions_list)
185 {
186 filename = dir + "/" + RTLIL::unescape_id(cell->type) + ext.first;
187 if (check_file_exists(filename)) {
188 Frontend::frontend_call(design, NULL, filename, ext.second);
189 goto loaded_module;
190 }
191 }
192 }
193
194 if ((flag_check || flag_simcheck) && cell->type[0] != '$')
195 log_error("Module `%s' referenced in module `%s' in cell `%s' is not part of the design.\n",
196 cell->type.c_str(), module->name.c_str(), cell->name.c_str());
197 continue;
198
199 loaded_module:
200 if (design->modules_.count(cell->type) == 0)
201 log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str());
202 did_something = true;
203 } else
204 if (flag_check || flag_simcheck)
205 {
206 RTLIL::Module *mod = design->module(cell->type);
207 for (auto &conn : cell->connections())
208 if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
209 int id = atoi(conn.first.c_str()+1);
210 if (id <= 0 || id > GetSize(mod->ports))
211 log_error("Module `%s' referenced in module `%s' in cell `%s' has only %d ports, requested port %d.\n",
212 log_id(cell->type), log_id(module), log_id(cell), GetSize(mod->ports), id);
213 } else if (mod->wire(conn.first) == nullptr || mod->wire(conn.first)->port_id == 0)
214 log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n",
215 log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first));
216 for (auto &param : cell->parameters)
217 if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$' && strchr(param.first.c_str(), '.') == NULL)
218 log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n",
219 log_id(cell->type), log_id(module), log_id(cell), log_id(param.first));
220 }
221
222 if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
223 if (flag_simcheck)
224 log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n",
225 cell->type.c_str(), module->name.c_str(), cell->name.c_str());
226 continue;
227 }
228
229 if (cell->parameters.size() == 0)
230 continue;
231
232 RTLIL::Module *mod = design->modules_[cell->type];
233 cell->type = mod->derive(design, cell->parameters);
234 cell->parameters.clear();
235 did_something = true;
236 }
237
238 for (auto &it : array_cells)
239 {
240 RTLIL::Cell *cell = it.first;
241 int idx = it.second.first, num = it.second.second;
242
243 if (design->modules_.count(cell->type) == 0)
244 log_error("Array cell `%s.%s' of unknown type `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
245
246 RTLIL::Module *mod = design->modules_[cell->type];
247
248 for (auto &conn : cell->connections_) {
249 int conn_size = conn.second.size();
250 RTLIL::IdString portname = conn.first;
251 if (portname.substr(0, 1) == "$") {
252 int port_id = atoi(portname.substr(1).c_str());
253 for (auto &wire_it : mod->wires_)
254 if (wire_it.second->port_id == port_id) {
255 portname = wire_it.first;
256 break;
257 }
258 }
259 if (mod->wires_.count(portname) == 0)
260 log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
261 int port_size = mod->wires_.at(portname)->width;
262 if (conn_size == port_size || conn_size == 0)
263 continue;
264 if (conn_size != port_size*num)
265 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));
266 conn.second = conn.second.extract(port_size*idx, port_size);
267 }
268 }
269
270 return did_something;
271 }
272
273 void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> &used, RTLIL::Module *mod, int indent)
274 {
275 if (used.count(mod) > 0)
276 return;
277
278 if (indent == 0)
279 log("Top module: %s\n", mod->name.c_str());
280 else if (!mod->get_bool_attribute("\\blackbox"))
281 log("Used module: %*s%s\n", indent, "", mod->name.c_str());
282 used.insert(mod);
283
284 for (auto cell : mod->cells()) {
285 std::string celltype = cell->type.str();
286 if (celltype.substr(0, 7) == "$array:") {
287 int pos_idx = celltype.find_first_of(':');
288 int pos_num = celltype.find_first_of(':', pos_idx + 1);
289 int pos_type = celltype.find_first_of(':', pos_num + 1);
290 celltype = celltype.substr(pos_type + 1);
291 }
292 if (design->module(celltype))
293 hierarchy_worker(design, used, design->module(celltype), indent+4);
294 }
295 }
296
297 void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
298 {
299 std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used;
300 hierarchy_worker(design, used, top, 0);
301
302 std::vector<RTLIL::Module*> del_modules;
303 for (auto &it : design->modules_)
304 if (used.count(it.second) == 0)
305 del_modules.push_back(it.second);
306
307 int del_counter = 0;
308 for (auto mod : del_modules) {
309 if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
310 continue;
311 log("Removing unused module `%s'.\n", mod->name.c_str());
312 design->modules_.erase(mod->name);
313 del_counter++;
314 delete mod;
315 }
316
317 log("Removed %d unused modules.\n", del_counter);
318 }
319
320 bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
321 {
322 if (cache.count(mod) == 0)
323 for (auto c : mod->cells()) {
324 RTLIL::Module *m = mod->design->module(c->type);
325 if ((m != nullptr && set_keep_assert(cache, m)) || c->type.in("$assert", "$assume", "$live", "$fair", "$cover"))
326 return cache[mod] = true;
327 }
328 return cache[mod];
329 }
330
331 int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
332 {
333 if (db.count(module) == 0) {
334 int score = 0;
335 db[module] = 0;
336 for (auto cell : module->cells())
337 if (design->module(cell->type))
338 score = max(score, find_top_mod_score(design, design->module(cell->type), db) + 1);
339 db[module] = score;
340 }
341 return db.at(module);
342 }
343
344 struct HierarchyPass : public Pass {
345 HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
346 virtual void help()
347 {
348 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
349 log("\n");
350 log(" hierarchy [-check] [-top <module>]\n");
351 log(" hierarchy -generate <cell-types> <port-decls>\n");
352 log("\n");
353 log("In parametric designs, a module might exists in several variations with\n");
354 log("different parameter values. This pass looks at all modules in the current\n");
355 log("design an re-runs the language frontends for the parametric modules as\n");
356 log("needed.\n");
357 log("\n");
358 log(" -check\n");
359 log(" also check the design hierarchy. this generates an error when\n");
360 log(" an unknown module is used as cell type.\n");
361 log("\n");
362 log(" -simcheck\n");
363 log(" like -check, but also thow an error if blackbox modules are\n");
364 log(" instantiated, and throw an error if the design has no top module\n");
365 log("\n");
366 log(" -purge_lib\n");
367 log(" by default the hierarchy command will not remove library (blackbox)\n");
368 log(" modules. use this option to also remove unused blackbox modules.\n");
369 log("\n");
370 log(" -libdir <directory>\n");
371 log(" search for files named <module_name>.v in the specified directory\n");
372 log(" for unknown modules and automatically run read_verilog for each\n");
373 log(" unknown module.\n");
374 log("\n");
375 log(" -keep_positionals\n");
376 log(" per default this pass also converts positional arguments in cells\n");
377 log(" to arguments using port names. this option disables this behavior.\n");
378 log("\n");
379 log(" -keep_portwidths\n");
380 log(" per default this pass adjusts the port width on cells that are\n");
381 log(" module instances when the width does not match the module port. this\n");
382 log(" option disables this behavior.\n");
383 log("\n");
384 log(" -nokeep_asserts\n");
385 log(" per default this pass sets the \"keep\" attribute on all modules\n");
386 log(" that directly or indirectly contain one or more $assert cells. this\n");
387 log(" option disables this behavior.\n");
388 log("\n");
389 log(" -top <module>\n");
390 log(" use the specified top module to built a design hierarchy. modules\n");
391 log(" outside this tree (unused modules) are removed.\n");
392 log("\n");
393 log(" when the -top option is used, the 'top' attribute will be set on the\n");
394 log(" specified top module. otherwise a module with the 'top' attribute set\n");
395 log(" will implicitly be used as top module, if such a module exists.\n");
396 log("\n");
397 log(" -auto-top\n");
398 log(" automatically determine the top of the design hierarchy and mark it.\n");
399 log("\n");
400 log("In -generate mode this pass generates blackbox modules for the given cell\n");
401 log("types (wildcards supported). For this the design is searched for cells that\n");
402 log("match the given types and then the given port declarations are used to\n");
403 log("determine the direction of the ports. The syntax for a port declaration is:\n");
404 log("\n");
405 log(" {i|o|io}[@<num>]:<portname>\n");
406 log("\n");
407 log("Input ports are specified with the 'i' prefix, output ports with the 'o'\n");
408 log("prefix and inout ports with the 'io' prefix. The optional <num> specifies\n");
409 log("the position of the port in the parameter list (needed when instantiated\n");
410 log("using positional arguments). When <num> is not specified, the <portname> can\n");
411 log("also contain wildcard characters.\n");
412 log("\n");
413 log("This pass ignores the current selection and always operates on all modules\n");
414 log("in the current design.\n");
415 log("\n");
416 }
417 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
418 {
419 log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n");
420
421 bool flag_check = false;
422 bool flag_simcheck = false;
423 bool purge_lib = false;
424 RTLIL::Module *top_mod = NULL;
425 std::string load_top_mod;
426 std::vector<std::string> libdirs;
427
428 bool auto_top_mode = false;
429 bool generate_mode = false;
430 bool keep_positionals = false;
431 bool keep_portwidths = false;
432 bool nokeep_asserts = false;
433 std::vector<std::string> generate_cells;
434 std::vector<generate_port_decl_t> generate_ports;
435
436 size_t argidx;
437 for (argidx = 1; argidx < args.size(); argidx++)
438 {
439 if (args[argidx] == "-generate" && !flag_check && !flag_simcheck && !top_mod) {
440 generate_mode = true;
441 log("Entering generate mode.\n");
442 while (++argidx < args.size()) {
443 const char *p = args[argidx].c_str();
444 generate_port_decl_t decl;
445 if (p[0] == 'i' && p[1] == 'o')
446 decl.input = true, decl.output = true, p += 2;
447 else if (*p == 'i')
448 decl.input = true, decl.output = false, p++;
449 else if (*p == 'o')
450 decl.input = false, decl.output = true, p++;
451 else
452 goto is_celltype;
453 if (*p == '@') {
454 char *endptr;
455 decl.index = strtol(++p, &endptr, 10);
456 if (decl.index < 1)
457 goto is_celltype;
458 p = endptr;
459 } else
460 decl.index = 0;
461 if (*(p++) != ':')
462 goto is_celltype;
463 if (*p == 0)
464 goto is_celltype;
465 decl.portname = p;
466 log("Port declaration: %s", decl.input ? decl.output ? "inout" : "input" : "output");
467 if (decl.index >= 1)
468 log(" [at position %d]", decl.index);
469 log(" %s\n", decl.portname.c_str());
470 generate_ports.push_back(decl);
471 continue;
472 is_celltype:
473 log("Celltype: %s\n", args[argidx].c_str());
474 generate_cells.push_back(RTLIL::unescape_id(args[argidx]));
475 }
476 continue;
477 }
478 if (args[argidx] == "-check") {
479 flag_check = true;
480 continue;
481 }
482 if (args[argidx] == "-simcheck") {
483 flag_simcheck = true;
484 continue;
485 }
486 if (args[argidx] == "-purge_lib") {
487 purge_lib = true;
488 continue;
489 }
490 if (args[argidx] == "-keep_positionals") {
491 keep_positionals = true;
492 continue;
493 }
494 if (args[argidx] == "-keep_portwidths") {
495 keep_portwidths = true;
496 continue;
497 }
498 if (args[argidx] == "-nokeep_asserts") {
499 nokeep_asserts = true;
500 continue;
501 }
502 if (args[argidx] == "-libdir" && argidx+1 < args.size()) {
503 libdirs.push_back(args[++argidx]);
504 continue;
505 }
506 if (args[argidx] == "-top") {
507 if (++argidx >= args.size())
508 log_cmd_error("Option -top requires an additional argument!\n");
509 top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
510 if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
511 dict<RTLIL::IdString, RTLIL::Const> empty_parameters;
512 design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
513 top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
514 }
515 if (top_mod == NULL)
516 load_top_mod = args[argidx];
517 continue;
518 }
519 if (args[argidx] == "-auto-top") {
520 auto_top_mode = true;
521 continue;
522 }
523 break;
524 }
525 extra_args(args, argidx, design, false);
526
527 if (!load_top_mod.empty()) {
528 #ifdef YOSYS_ENABLE_VERIFIC
529 if (verific_import_pending) {
530 verific_import(design, load_top_mod);
531 top_mod = design->module(RTLIL::escape_id(load_top_mod));
532 }
533 #endif
534 if (top_mod == NULL)
535 log_cmd_error("Module `%s' not found!\n", load_top_mod.c_str());
536 } else {
537 #ifdef YOSYS_ENABLE_VERIFIC
538 if (verific_import_pending)
539 verific_import(design);
540 #endif
541 }
542
543 if (generate_mode) {
544 generate(design, generate_cells, generate_ports);
545 return;
546 }
547
548 log_push();
549
550 if (top_mod == nullptr)
551 for (auto &mod_it : design->modules_)
552 if (mod_it.second->get_bool_attribute("\\top"))
553 top_mod = mod_it.second;
554
555 if (top_mod == nullptr && auto_top_mode) {
556 log_header(design, "Finding top of design hierarchy..\n");
557 dict<Module*, int> db;
558 for (Module *mod : design->selected_modules()) {
559 int score = find_top_mod_score(design, mod, db);
560 log("root of %3d design levels: %-20s\n", score, log_id(mod));
561 if (!top_mod || score > db[top_mod])
562 top_mod = mod;
563 }
564 if (top_mod != nullptr)
565 log("Automatically selected %s as design top module.\n", log_id(top_mod));
566 }
567
568 if (flag_simcheck && top_mod == nullptr)
569 log_error("Design has no top module.\n");
570
571 bool did_something = true;
572 while (did_something)
573 {
574 did_something = false;
575
576 std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used_modules;
577 if (top_mod != NULL) {
578 log_header(design, "Analyzing design hierarchy..\n");
579 hierarchy_worker(design, used_modules, top_mod, 0);
580 } else {
581 for (auto mod : design->modules())
582 used_modules.insert(mod);
583 }
584
585 for (auto module : used_modules) {
586 if (expand_module(design, module, flag_check, flag_simcheck, libdirs))
587 did_something = true;
588 }
589 }
590
591 if (top_mod != NULL) {
592 log_header(design, "Analyzing design hierarchy..\n");
593 hierarchy_clean(design, top_mod, purge_lib);
594 }
595
596 if (top_mod != NULL) {
597 for (auto &mod_it : design->modules_)
598 if (mod_it.second == top_mod)
599 mod_it.second->attributes["\\top"] = RTLIL::Const(1);
600 else
601 mod_it.second->attributes.erase("\\top");
602 }
603
604 if (!nokeep_asserts) {
605 std::map<RTLIL::Module*, bool> cache;
606 for (auto mod : design->modules())
607 if (set_keep_assert(cache, mod)) {
608 log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod));
609 mod->set_bool_attribute("\\keep");
610 }
611 }
612
613 if (!keep_positionals)
614 {
615 std::set<RTLIL::Module*> pos_mods;
616 std::map<std::pair<RTLIL::Module*,int>, RTLIL::IdString> pos_map;
617 std::vector<std::pair<RTLIL::Module*,RTLIL::Cell*>> pos_work;
618
619 for (auto &mod_it : design->modules_)
620 for (auto &cell_it : mod_it.second->cells_) {
621 RTLIL::Cell *cell = cell_it.second;
622 if (design->modules_.count(cell->type) == 0)
623 continue;
624 for (auto &conn : cell->connections())
625 if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
626 pos_mods.insert(design->modules_.at(cell->type));
627 pos_work.push_back(std::pair<RTLIL::Module*,RTLIL::Cell*>(mod_it.second, cell));
628 break;
629 }
630 }
631
632 for (auto module : pos_mods)
633 for (auto &wire_it : module->wires_) {
634 RTLIL::Wire *wire = wire_it.second;
635 if (wire->port_id > 0)
636 pos_map[std::pair<RTLIL::Module*,int>(module, wire->port_id)] = wire->name;
637 }
638
639 for (auto &work : pos_work) {
640 RTLIL::Module *module = work.first;
641 RTLIL::Cell *cell = work.second;
642 log("Mapping positional arguments of cell %s.%s (%s).\n",
643 RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
644 dict<RTLIL::IdString, RTLIL::SigSpec> new_connections;
645 for (auto &conn : cell->connections())
646 if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
647 int id = atoi(conn.first.c_str()+1);
648 std::pair<RTLIL::Module*,int> key(design->modules_.at(cell->type), id);
649 if (pos_map.count(key) == 0) {
650 log(" Failed to map positional argument %d of cell %s.%s (%s).\n",
651 id, RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
652 new_connections[conn.first] = conn.second;
653 } else
654 new_connections[pos_map.at(key)] = conn.second;
655 } else
656 new_connections[conn.first] = conn.second;
657 cell->connections_ = new_connections;
658 }
659 }
660
661 std::set<Module*> blackbox_derivatives;
662 std::vector<Module*> design_modules = design->modules();
663
664 for (auto module : design_modules)
665 for (auto cell : module->cells())
666 {
667 Module *m = design->module(cell->type);
668
669 if (m == nullptr)
670 continue;
671
672 if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty()) {
673 IdString new_m_name = m->derive(design, cell->parameters, true);
674 if (new_m_name.empty())
675 continue;
676 if (new_m_name != m->name) {
677 m = design->module(new_m_name);
678 blackbox_derivatives.insert(m);
679 }
680 }
681
682 for (auto &conn : cell->connections())
683 {
684 Wire *w = m->wire(conn.first);
685
686 if (w == nullptr || w->port_id == 0)
687 continue;
688
689 if (GetSize(conn.second) == 0)
690 continue;
691
692 SigSpec sig = conn.second;
693
694 if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
695 {
696 if (GetSize(w) < GetSize(conn.second))
697 {
698 int n = GetSize(conn.second) - GetSize(w);
699 if (!w->port_input && w->port_output)
700 module->connect(sig.extract(GetSize(w), n), Const(0, n));
701 sig.remove(GetSize(w), n);
702 }
703 else
704 {
705 int n = GetSize(w) - GetSize(conn.second);
706 if (w->port_input && !w->port_output)
707 sig.append(Const(0, n));
708 else
709 sig.append(module->addWire(NEW_ID, n));
710 }
711
712 if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
713 log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
714 log_id(conn.first), GetSize(conn.second), GetSize(sig));
715 cell->setPort(conn.first, sig);
716 }
717
718 if (w->port_output && !w->port_input && sig.has_const())
719 log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
720 log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
721 }
722 }
723
724 for (auto module : blackbox_derivatives)
725 design->remove(module);
726
727 log_pop();
728 }
729 } HierarchyPass;
730
731 PRIVATE_NAMESPACE_END