2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
20 #include "kernel/yosys.h"
21 #include "frontends/verific/verific.h"
32 PRIVATE_NAMESPACE_BEGIN
34 struct generate_port_decl_t
{
40 void generate(RTLIL::Design
*design
, const std::vector
<std::string
> &celltypes
, const std::vector
<generate_port_decl_t
> &portdecls
)
42 std::set
<RTLIL::IdString
> found_celltypes
;
44 for (auto i1
: design
->modules_
)
45 for (auto i2
: i1
.second
->cells_
)
47 RTLIL::Cell
*cell
= i2
.second
;
48 if (design
->has(cell
->type
))
50 if (cell
->type
.substr(0, 1) == "$" && cell
->type
.substr(0, 3) != "$__")
52 for (auto &pattern
: celltypes
)
53 if (patmatch(pattern
.c_str(), RTLIL::unescape_id(cell
->type
).c_str()))
54 found_celltypes
.insert(cell
->type
);
57 for (auto &celltype
: found_celltypes
)
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());
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());
72 for (auto ¶
: i2
.second
->parameters
)
73 parameters
.insert(para
.first
);
76 for (auto &decl
: portdecls
)
78 portnames
.insert(decl
.portname
);
80 std::set
<int> indices
;
81 for (int i
= 0; i
< int(portnames
.size()); i
++)
84 std::vector
<generate_port_decl_t
> ports(portnames
.size());
86 for (auto &decl
: portdecls
)
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
;
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
;
114 log_error("Can't match port %s.\n", RTLIL::id2cstr(portname
));
115 found_matching_decl
:;
116 portnames
.erase(portname
);
119 log_assert(indices
.empty());
121 RTLIL::Module
*mod
= new RTLIL::Module
;
122 mod
->name
= celltype
;
123 mod
->attributes
["\\blackbox"] = RTLIL::Const(1);
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
;
135 for (auto ¶
: parameters
)
136 log(" ignoring parameter %s.\n", RTLIL::id2cstr(para
));
138 log(" module %s created.\n", RTLIL::id2cstr(mod
->name
));
142 bool expand_module(RTLIL::Design
*design
, RTLIL::Module
*module
, bool flag_check
, bool flag_simcheck
, std::vector
<std::string
> &libdirs
)
144 bool did_something
= false;
145 std::map
<RTLIL::Cell
*, std::pair
<int, int>> array_cells
;
146 std::string filename
;
148 for (auto &cell_it
: module
->cells_
)
150 RTLIL::Cell
*cell
= cell_it
.second
;
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);
162 if (design
->modules_
.count(cell
->type
) == 0)
164 if (design
->modules_
.count("$abstract" + cell
->type
.str()))
166 cell
->type
= design
->modules_
.at("$abstract" + cell
->type
.str())->derive(design
, cell
->parameters
);
167 cell
->parameters
.clear();
168 did_something
= true;
172 if (cell
->type
[0] == '$')
175 for (auto &dir
: libdirs
)
177 static const vector
<pair
<string
, string
>> extensions_list
=
180 {".sv", "verilog -sv"},
184 for (auto &ext
: extensions_list
)
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
);
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());
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;
204 if (flag_check
|| flag_simcheck
)
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 ¶m
: 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
));
222 if (design
->modules_
.at(cell
->type
)->get_bool_attribute("\\blackbox")) {
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());
229 if (cell
->parameters
.size() == 0)
232 RTLIL::Module
*mod
= design
->modules_
[cell
->type
];
233 cell
->type
= mod
->derive(design
, cell
->parameters
);
234 cell
->parameters
.clear();
235 did_something
= true;
238 for (auto &it
: array_cells
)
240 RTLIL::Cell
*cell
= it
.first
;
241 int idx
= it
.second
.first
, num
= it
.second
.second
;
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
));
246 RTLIL::Module
*mod
= design
->modules_
[cell
->type
];
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
;
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)
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
);
270 return did_something
;
273 void hierarchy_worker(RTLIL::Design
*design
, std::set
<RTLIL::Module
*, IdString::compare_ptr_by_name
<Module
>> &used
, RTLIL::Module
*mod
, int indent
)
275 if (used
.count(mod
) > 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());
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);
292 if (design
->module(celltype
))
293 hierarchy_worker(design
, used
, design
->module(celltype
), indent
+4);
297 void hierarchy_clean(RTLIL::Design
*design
, RTLIL::Module
*top
, bool purge_lib
)
299 std::set
<RTLIL::Module
*, IdString::compare_ptr_by_name
<Module
>> used
;
300 hierarchy_worker(design
, used
, top
, 0);
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
);
308 for (auto mod
: del_modules
) {
309 if (!purge_lib
&& mod
->get_bool_attribute("\\blackbox"))
311 log("Removing unused module `%s'.\n", mod
->name
.c_str());
312 design
->modules_
.erase(mod
->name
);
317 log("Removed %d unused modules.\n", del_counter
);
320 bool set_keep_assert(std::map
<RTLIL::Module
*, bool> &cache
, RTLIL::Module
*mod
)
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;
331 int find_top_mod_score(Design
*design
, Module
*module
, dict
<Module
*, int> &db
)
333 if (db
.count(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);
341 return db
.at(module
);
344 struct HierarchyPass
: public Pass
{
345 HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
348 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
350 log(" hierarchy [-check] [-top <module>]\n");
351 log(" hierarchy -generate <cell-types> <port-decls>\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");
359 log(" also check the design hierarchy. this generates an error when\n");
360 log(" an unknown module is used as cell type.\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");
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");
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");
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");
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");
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");
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");
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");
398 log(" automatically determine the top of the design hierarchy and mark it.\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");
405 log(" {i|o|io}[@<num>]:<portname>\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");
413 log("This pass ignores the current selection and always operates on all modules\n");
414 log("in the current design.\n");
417 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
419 log_header(design
, "Executing HIERARCHY pass (managing design hierarchy).\n");
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
;
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
;
437 for (argidx
= 1; argidx
< args
.size(); argidx
++)
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;
448 decl
.input
= true, decl
.output
= false, p
++;
450 decl
.input
= false, decl
.output
= true, p
++;
455 decl
.index
= strtol(++p
, &endptr
, 10);
466 log("Port declaration: %s", decl
.input
? decl
.output
? "inout" : "input" : "output");
468 log(" [at position %d]", decl
.index
);
469 log(" %s\n", decl
.portname
.c_str());
470 generate_ports
.push_back(decl
);
473 log("Celltype: %s\n", args
[argidx
].c_str());
474 generate_cells
.push_back(RTLIL::unescape_id(args
[argidx
]));
478 if (args
[argidx
] == "-check") {
482 if (args
[argidx
] == "-simcheck") {
483 flag_simcheck
= true;
486 if (args
[argidx
] == "-purge_lib") {
490 if (args
[argidx
] == "-keep_positionals") {
491 keep_positionals
= true;
494 if (args
[argidx
] == "-keep_portwidths") {
495 keep_portwidths
= true;
498 if (args
[argidx
] == "-nokeep_asserts") {
499 nokeep_asserts
= true;
502 if (args
[argidx
] == "-libdir" && argidx
+1 < args
.size()) {
503 libdirs
.push_back(args
[++argidx
]);
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
;
516 load_top_mod
= args
[argidx
];
519 if (args
[argidx
] == "-auto-top") {
520 auto_top_mode
= true;
525 extra_args(args
, argidx
, design
, false);
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
));
535 log_cmd_error("Module `%s' not found!\n", load_top_mod
.c_str());
537 #ifdef YOSYS_ENABLE_VERIFIC
538 if (verific_import_pending
)
539 verific_import(design
);
544 generate(design
, generate_cells
, generate_ports
);
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
;
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
])
564 if (top_mod
!= nullptr)
565 log("Automatically selected %s as design top module.\n", log_id(top_mod
));
568 if (flag_simcheck
&& top_mod
== nullptr)
569 log_error("Design has no top module.\n");
571 bool did_something
= true;
572 while (did_something
)
574 did_something
= false;
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);
581 for (auto mod
: design
->modules())
582 used_modules
.insert(mod
);
585 for (auto module
: used_modules
) {
586 if (expand_module(design
, module
, flag_check
, flag_simcheck
, libdirs
))
587 did_something
= true;
591 if (top_mod
!= NULL
) {
592 log_header(design
, "Analyzing design hierarchy..\n");
593 hierarchy_clean(design
, top_mod
, purge_lib
);
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);
601 mod_it
.second
->attributes
.erase("\\top");
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");
613 if (!keep_positionals
)
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
;
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)
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
));
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
;
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
;
654 new_connections
[pos_map
.at(key
)] = conn
.second
;
656 new_connections
[conn
.first
] = conn
.second
;
657 cell
->connections_
= new_connections
;
661 std::set
<Module
*> blackbox_derivatives
;
662 std::vector
<Module
*> design_modules
= design
->modules();
664 for (auto module
: design_modules
)
665 for (auto cell
: module
->cells())
667 Module
*m
= design
->module(cell
->type
);
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())
676 if (new_m_name
!= m
->name
) {
677 m
= design
->module(new_m_name
);
678 blackbox_derivatives
.insert(m
);
682 for (auto &conn
: cell
->connections())
684 Wire
*w
= m
->wire(conn
.first
);
686 if (w
== nullptr || w
->port_id
== 0)
689 if (GetSize(conn
.second
) == 0)
692 SigSpec sig
= conn
.second
;
694 if (!keep_portwidths
&& GetSize(w
) != GetSize(conn
.second
))
696 if (GetSize(w
) < GetSize(conn
.second
))
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
);
705 int n
= GetSize(w
) - GetSize(conn
.second
);
706 if (w
->port_input
&& !w
->port_output
)
707 sig
.append(Const(0, n
));
709 sig
.append(module
->addWire(NEW_ID
, n
));
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
);
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
));
724 for (auto module
: blackbox_derivatives
)
725 design
->remove(module
);
731 PRIVATE_NAMESPACE_END