Added avail params to ilang format, check module params in 'hierarchy -check'
[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 <stdlib.h>
22 #include <stdio.h>
23 #include <set>
24
25 #ifndef _WIN32
26 # include <unistd.h>
27 #endif
28
29
30 USING_YOSYS_NAMESPACE
31 PRIVATE_NAMESPACE_BEGIN
32
33 struct generate_port_decl_t {
34 bool input, output;
35 string portname;
36 int index;
37 };
38
39 void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, const std::vector<generate_port_decl_t> &portdecls)
40 {
41 std::set<RTLIL::IdString> found_celltypes;
42
43 for (auto i1 : design->modules_)
44 for (auto i2 : i1.second->cells_)
45 {
46 RTLIL::Cell *cell = i2.second;
47 if (design->has(cell->type))
48 continue;
49 if (cell->type.substr(0, 1) == "$" && cell->type.substr(0, 3) != "$__")
50 continue;
51 for (auto &pattern : celltypes)
52 if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str()))
53 found_celltypes.insert(cell->type);
54 }
55
56 for (auto &celltype : found_celltypes)
57 {
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());
62
63 for (auto i1 : design->modules_)
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] = max(portwidths[conn.first], conn.second.size());
70 }
71 for (auto &para : i2.second->parameters)
72 parameters.insert(para.first);
73 }
74
75 for (auto &decl : portdecls)
76 if (decl.index > 0)
77 portnames.insert(decl.portname);
78
79 std::set<int> indices;
80 for (int i = 0; i < int(portnames.size()); i++)
81 indices.insert(i+1);
82
83 std::vector<generate_port_decl_t> ports(portnames.size());
84
85 for (auto &decl : portdecls)
86 if (decl.index > 0) {
87 portwidths[decl.portname] = max(portwidths[decl.portname], 1);
88 portwidths[decl.portname] = 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;
97 }
98
99 while (portnames.size() > 0) {
100 RTLIL::IdString portname = *portnames.begin();
101 for (auto &decl : portdecls)
102 if (decl.index == 0 && patmatch(decl.portname.c_str(), RTLIL::unescape_id(portname).c_str())) {
103 generate_port_decl_t d = decl;
104 d.portname = portname.str();
105 d.index = *indices.begin();
106 log_assert(!indices.empty());
107 indices.erase(d.index);
108 ports[d.index-1] = d;
109 portwidths[d.portname] = max(portwidths[d.portname], 1);
110 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));
111 goto found_matching_decl;
112 }
113 log_error("Can't match port %s.\n", RTLIL::id2cstr(portname));
114 found_matching_decl:;
115 portnames.erase(portname);
116 }
117
118 log_assert(indices.empty());
119
120 RTLIL::Module *mod = new RTLIL::Module;
121 mod->name = celltype;
122 mod->attributes["\\blackbox"] = RTLIL::Const(1);
123 design->add(mod);
124
125 for (auto &decl : ports) {
126 RTLIL::Wire *wire = mod->addWire(decl.portname, portwidths.at(decl.portname));
127 wire->port_id = decl.index;
128 wire->port_input = decl.input;
129 wire->port_output = decl.output;
130 }
131
132 mod->fixup_ports();
133
134 for (auto &para : parameters)
135 log(" ignoring parameter %s.\n", RTLIL::id2cstr(para));
136
137 log(" module %s created.\n", RTLIL::id2cstr(mod->name));
138 }
139 }
140
141 bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
142 {
143 bool did_something = false;
144 std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
145 std::string filename;
146
147 for (auto &cell_it : module->cells_)
148 {
149 RTLIL::Cell *cell = cell_it.second;
150
151 if (cell->type.substr(0, 7) == "$array:") {
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);
159 }
160
161 if (design->modules_.count(cell->type) == 0)
162 {
163 if (design->modules_.count("$abstract" + cell->type.str()))
164 {
165 cell->type = design->modules_.at("$abstract" + cell->type.str())->derive(design, cell->parameters);
166 cell->parameters.clear();
167 did_something = true;
168 continue;
169 }
170
171 if (cell->type[0] == '$')
172 continue;
173
174 for (auto &dir : libdirs)
175 {
176 filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
177 if (check_file_exists(filename)) {
178 std::vector<std::string> args;
179 args.push_back(filename);
180 Frontend::frontend_call(design, NULL, filename, "verilog");
181 goto loaded_module;
182 }
183
184 filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
185 if (check_file_exists(filename)) {
186 std::vector<std::string> args;
187 args.push_back(filename);
188 Frontend::frontend_call(design, NULL, filename, "ilang");
189 goto loaded_module;
190 }
191 }
192
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",
195 cell->type.c_str(), module->name.c_str(), cell->name.c_str());
196 continue;
197
198 loaded_module:
199 if (design->modules_.count(cell->type) == 0)
200 log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str());
201 did_something = true;
202 } else
203 if (flag_check)
204 {
205 RTLIL::Module *mod = design->module(cell->type);
206 for (auto &conn : cell->connections())
207 if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
208 int id = atoi(conn.first.c_str()+1);
209 if (id <= 0 || id > GetSize(mod->ports))
210 log_error("Module `%s' referenced in module `%s' in cell `%s' has only %d ports, requested port %d.\n",
211 log_id(cell->type), log_id(module), log_id(cell), GetSize(mod->ports), id);
212 } else if (mod->wire(conn.first) == nullptr || mod->wire(conn.first)->port_id == 0)
213 log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n",
214 log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first));
215 for (auto &param : cell->parameters)
216 if (mod->avail_parameters.count(param.first) == 0)
217 log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n",
218 log_id(cell->type), log_id(module), log_id(cell), log_id(param.first));
219 }
220
221 if (cell->parameters.size() == 0)
222 continue;
223
224 if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox"))
225 continue;
226
227 RTLIL::Module *mod = design->modules_[cell->type];
228 cell->type = mod->derive(design, cell->parameters);
229 cell->parameters.clear();
230 did_something = true;
231 }
232
233 for (auto &it : array_cells)
234 {
235 RTLIL::Cell *cell = it.first;
236 int idx = it.second.first, num = it.second.second;
237
238 if (design->modules_.count(cell->type) == 0)
239 log_error("Array cell `%s.%s' of unknown type `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
240
241 RTLIL::Module *mod = design->modules_[cell->type];
242
243 for (auto &conn : cell->connections_) {
244 int conn_size = conn.second.size();
245 RTLIL::IdString portname = conn.first;
246 if (portname.substr(0, 1) == "$") {
247 int port_id = atoi(portname.substr(1).c_str());
248 for (auto &wire_it : mod->wires_)
249 if (wire_it.second->port_id == port_id) {
250 portname = wire_it.first;
251 break;
252 }
253 }
254 if (mod->wires_.count(portname) == 0)
255 log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
256 int port_size = mod->wires_.at(portname)->width;
257 if (conn_size == port_size)
258 continue;
259 if (conn_size != port_size*num)
260 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));
261 conn.second = conn.second.extract(port_size*idx, port_size);
262 }
263 }
264
265 return did_something;
266 }
267
268 void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> &used, RTLIL::Module *mod, int indent)
269 {
270 if (used.count(mod) > 0)
271 return;
272
273 if (indent == 0)
274 log("Top module: %s\n", mod->name.c_str());
275 else if (!mod->get_bool_attribute("\\blackbox"))
276 log("Used module: %*s%s\n", indent, "", mod->name.c_str());
277 used.insert(mod);
278
279 for (auto cell : mod->cells()) {
280 std::string celltype = cell->type.str();
281 if (celltype.substr(0, 7) == "$array:") {
282 int pos_idx = celltype.find_first_of(':');
283 int pos_num = celltype.find_first_of(':', pos_idx + 1);
284 int pos_type = celltype.find_first_of(':', pos_num + 1);
285 celltype = celltype.substr(pos_type + 1);
286 }
287 if (design->module(celltype))
288 hierarchy_worker(design, used, design->module(celltype), indent+4);
289 }
290 }
291
292 void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
293 {
294 std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used;
295 hierarchy_worker(design, used, top, 0);
296
297 std::vector<RTLIL::Module*> del_modules;
298 for (auto &it : design->modules_)
299 if (used.count(it.second) == 0)
300 del_modules.push_back(it.second);
301
302 int del_counter = 0;
303 for (auto mod : del_modules) {
304 if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
305 continue;
306 log("Removing unused module `%s'.\n", mod->name.c_str());
307 design->modules_.erase(mod->name);
308 del_counter++;
309 delete mod;
310 }
311
312 log("Removed %d unused modules.\n", del_counter);
313 }
314
315 bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
316 {
317 if (cache.count(mod) == 0)
318 for (auto c : mod->cells()) {
319 RTLIL::Module *m = mod->design->module(c->type);
320 if ((m != nullptr && set_keep_assert(cache, m)) || c->type.in("$assert", "$assume"))
321 return cache[mod] = true;
322 }
323 return cache[mod];
324 }
325
326 int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
327 {
328 if (db.count(module) == 0) {
329 int score = 0;
330 db[module] = 0;
331 for (auto cell : module->cells())
332 if (design->module(cell->type))
333 score = max(score, find_top_mod_score(design, design->module(cell->type), db) + 1);
334 db[module] = score;
335 }
336 return db.at(module);
337 }
338
339 struct HierarchyPass : public Pass {
340 HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
341 virtual void help()
342 {
343 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
344 log("\n");
345 log(" hierarchy [-check] [-top <module>]\n");
346 log(" hierarchy -generate <cell-types> <port-decls>\n");
347 log("\n");
348 log("In parametric designs, a module might exists in several variations with\n");
349 log("different parameter values. This pass looks at all modules in the current\n");
350 log("design an re-runs the language frontends for the parametric modules as\n");
351 log("needed.\n");
352 log("\n");
353 log(" -check\n");
354 log(" also check the design hierarchy. this generates an error when\n");
355 log(" an unknown module is used as cell type.\n");
356 log("\n");
357 log(" -purge_lib\n");
358 log(" by default the hierarchy command will not remove library (blackbox)\n");
359 log(" modules. use this option to also remove unused blackbox modules.\n");
360 log("\n");
361 log(" -libdir <directory>\n");
362 log(" search for files named <module_name>.v in the specified directory\n");
363 log(" for unknown modules and automatically run read_verilog for each\n");
364 log(" unknown module.\n");
365 log("\n");
366 log(" -keep_positionals\n");
367 log(" per default this pass also converts positional arguments in cells\n");
368 log(" to arguments using port names. this option disables this behavior.\n");
369 log("\n");
370 log(" -nokeep_asserts\n");
371 log(" per default this pass sets the \"keep\" attribute on all modules\n");
372 log(" that directly or indirectly contain one or more $assert cells. this\n");
373 log(" option disables this behavior.\n");
374 log("\n");
375 log(" -top <module>\n");
376 log(" use the specified top module to built a design hierarchy. modules\n");
377 log(" outside this tree (unused modules) are removed.\n");
378 log("\n");
379 log(" when the -top option is used, the 'top' attribute will be set on the\n");
380 log(" specified top module. otherwise a module with the 'top' attribute set\n");
381 log(" will implicitly be used as top module, if such a module exists.\n");
382 log("\n");
383 log(" -auto-top\n");
384 log(" automatically determine the top of the design hierarchy and mark it.\n");
385 log("\n");
386 log("In -generate mode this pass generates blackbox modules for the given cell\n");
387 log("types (wildcards supported). For this the design is searched for cells that\n");
388 log("match the given types and then the given port declarations are used to\n");
389 log("determine the direction of the ports. The syntax for a port declaration is:\n");
390 log("\n");
391 log(" {i|o|io}[@<num>]:<portname>\n");
392 log("\n");
393 log("Input ports are specified with the 'i' prefix, output ports with the 'o'\n");
394 log("prefix and inout ports with the 'io' prefix. The optional <num> specifies\n");
395 log("the position of the port in the parameter list (needed when instantiated\n");
396 log("using positional arguments). When <num> is not specified, the <portname> can\n");
397 log("also contain wildcard characters.\n");
398 log("\n");
399 log("This pass ignores the current selection and always operates on all modules\n");
400 log("in the current design.\n");
401 log("\n");
402 }
403 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
404 {
405 log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n");
406
407 bool flag_check = false;
408 bool purge_lib = false;
409 RTLIL::Module *top_mod = NULL;
410 std::vector<std::string> libdirs;
411
412 bool auto_top_mode = false;
413 bool generate_mode = false;
414 bool keep_positionals = false;
415 bool nokeep_asserts = false;
416 std::vector<std::string> generate_cells;
417 std::vector<generate_port_decl_t> generate_ports;
418
419 size_t argidx;
420 for (argidx = 1; argidx < args.size(); argidx++)
421 {
422 if (args[argidx] == "-generate" && !flag_check && !top_mod) {
423 generate_mode = true;
424 log("Entering generate mode.\n");
425 while (++argidx < args.size()) {
426 const char *p = args[argidx].c_str();
427 generate_port_decl_t decl;
428 if (p[0] == 'i' && p[1] == 'o')
429 decl.input = true, decl.output = true, p += 2;
430 else if (*p == 'i')
431 decl.input = true, decl.output = false, p++;
432 else if (*p == 'o')
433 decl.input = false, decl.output = true, p++;
434 else
435 goto is_celltype;
436 if (*p == '@') {
437 char *endptr;
438 decl.index = strtol(++p, &endptr, 10);
439 if (decl.index < 1)
440 goto is_celltype;
441 p = endptr;
442 } else
443 decl.index = 0;
444 if (*(p++) != ':')
445 goto is_celltype;
446 if (*p == 0)
447 goto is_celltype;
448 decl.portname = p;
449 log("Port declaration: %s", decl.input ? decl.output ? "inout" : "input" : "output");
450 if (decl.index >= 1)
451 log(" [at position %d]", decl.index);
452 log(" %s\n", decl.portname.c_str());
453 generate_ports.push_back(decl);
454 continue;
455 is_celltype:
456 log("Celltype: %s\n", args[argidx].c_str());
457 generate_cells.push_back(RTLIL::unescape_id(args[argidx]));
458 }
459 continue;
460 }
461 if (args[argidx] == "-check") {
462 flag_check = true;
463 continue;
464 }
465 if (args[argidx] == "-purge_lib") {
466 purge_lib = true;
467 continue;
468 }
469 if (args[argidx] == "-keep_positionals") {
470 keep_positionals = true;
471 continue;
472 }
473 if (args[argidx] == "-nokeep_asserts") {
474 nokeep_asserts = true;
475 continue;
476 }
477 if (args[argidx] == "-libdir" && argidx+1 < args.size()) {
478 libdirs.push_back(args[++argidx]);
479 continue;
480 }
481 if (args[argidx] == "-top") {
482 if (++argidx >= args.size())
483 log_cmd_error("Option -top requires an additional argument!\n");
484 top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
485 if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
486 dict<RTLIL::IdString, RTLIL::Const> empty_parameters;
487 design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
488 top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
489 }
490 if (top_mod == NULL)
491 log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
492 continue;
493 }
494 if (args[argidx] == "-auto-top") {
495 auto_top_mode = true;
496 continue;
497 }
498 break;
499 }
500 extra_args(args, argidx, design, false);
501
502 if (generate_mode) {
503 generate(design, generate_cells, generate_ports);
504 return;
505 }
506
507 log_push();
508
509 if (top_mod == nullptr)
510 for (auto &mod_it : design->modules_)
511 if (mod_it.second->get_bool_attribute("\\top"))
512 top_mod = mod_it.second;
513
514 if (top_mod == nullptr && auto_top_mode) {
515 log_header(design, "Finding top of design hierarchy..\n");
516 dict<Module*, int> db;
517 for (Module *mod : design->selected_modules()) {
518 int score = find_top_mod_score(design, mod, db);
519 log("root of %3d design levels: %-20s\n", score, log_id(mod));
520 if (!top_mod || score > db[top_mod])
521 top_mod = mod;
522 }
523 if (top_mod != nullptr)
524 log("Automatically selected %s as design top module.\n", log_id(top_mod));
525 }
526
527 bool did_something = true;
528 while (did_something)
529 {
530 did_something = false;
531
532 std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used_modules;
533 if (top_mod != NULL) {
534 log_header(design, "Analyzing design hierarchy..\n");
535 hierarchy_worker(design, used_modules, top_mod, 0);
536 } else {
537 for (auto mod : design->modules())
538 used_modules.insert(mod);
539 }
540
541 for (auto module : used_modules) {
542 if (expand_module(design, module, flag_check, libdirs))
543 did_something = true;
544 }
545 }
546
547 if (top_mod != NULL) {
548 log_header(design, "Analyzing design hierarchy..\n");
549 hierarchy_clean(design, top_mod, purge_lib);
550 }
551
552 if (top_mod != NULL) {
553 for (auto &mod_it : design->modules_)
554 if (mod_it.second == top_mod)
555 mod_it.second->attributes["\\top"] = RTLIL::Const(1);
556 else
557 mod_it.second->attributes.erase("\\top");
558 }
559
560 if (!nokeep_asserts) {
561 std::map<RTLIL::Module*, bool> cache;
562 for (auto mod : design->modules())
563 if (set_keep_assert(cache, mod)) {
564 log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod));
565 mod->set_bool_attribute("\\keep");
566 }
567 }
568
569 if (!keep_positionals)
570 {
571 std::set<RTLIL::Module*> pos_mods;
572 std::map<std::pair<RTLIL::Module*,int>, RTLIL::IdString> pos_map;
573 std::vector<std::pair<RTLIL::Module*,RTLIL::Cell*>> pos_work;
574
575 for (auto &mod_it : design->modules_)
576 for (auto &cell_it : mod_it.second->cells_) {
577 RTLIL::Cell *cell = cell_it.second;
578 if (design->modules_.count(cell->type) == 0)
579 continue;
580 for (auto &conn : cell->connections())
581 if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
582 pos_mods.insert(design->modules_.at(cell->type));
583 pos_work.push_back(std::pair<RTLIL::Module*,RTLIL::Cell*>(mod_it.second, cell));
584 break;
585 }
586 }
587
588 for (auto module : pos_mods)
589 for (auto &wire_it : module->wires_) {
590 RTLIL::Wire *wire = wire_it.second;
591 if (wire->port_id > 0)
592 pos_map[std::pair<RTLIL::Module*,int>(module, wire->port_id)] = wire->name;
593 }
594
595 for (auto &work : pos_work) {
596 RTLIL::Module *module = work.first;
597 RTLIL::Cell *cell = work.second;
598 log("Mapping positional arguments of cell %s.%s (%s).\n",
599 RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
600 dict<RTLIL::IdString, RTLIL::SigSpec> new_connections;
601 for (auto &conn : cell->connections())
602 if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
603 int id = atoi(conn.first.c_str()+1);
604 std::pair<RTLIL::Module*,int> key(design->modules_.at(cell->type), id);
605 if (pos_map.count(key) == 0) {
606 log(" Failed to map positional argument %d of cell %s.%s (%s).\n",
607 id, RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
608 new_connections[conn.first] = conn.second;
609 } else
610 new_connections[pos_map.at(key)] = conn.second;
611 } else
612 new_connections[conn.first] = conn.second;
613 cell->connections_ = new_connections;
614 }
615 }
616
617 log_pop();
618 }
619 } HierarchyPass;
620
621 PRIVATE_NAMESPACE_END