Reorder steps in -auto-top to fix synth command, fixes #3261
[yosys.git] / passes / hierarchy / hierarchy.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
5 * Copyright (C) 2018 Ruben Undheim <ruben.undheim@gmail.com>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21 #include "kernel/yosys.h"
22 #include "frontends/verific/verific.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <set>
26
27 #ifndef _WIN32
28 # include <unistd.h>
29 #endif
30
31
32 USING_YOSYS_NAMESPACE
33 PRIVATE_NAMESPACE_BEGIN
34
35 struct generate_port_decl_t {
36 bool input, output;
37 string portname;
38 int index;
39 };
40
41 void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, const std::vector<generate_port_decl_t> &portdecls)
42 {
43 std::set<RTLIL::IdString> found_celltypes;
44
45 for (auto mod : design->modules())
46 for (auto cell : mod->cells())
47 {
48 if (design->module(cell->type) != nullptr)
49 continue;
50 if (cell->type.begins_with("$__"))
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 mod : design->modules())
65 for (auto cell : mod->cells())
66 if (cell->type == celltype) {
67 for (auto &conn : cell->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 : cell->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[ID::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 // Return the "basic" type for an array item.
143 std::string basic_cell_type(const std::string celltype, int pos[3] = nullptr) {
144 std::string basicType = celltype;
145 if (celltype.compare(0, strlen("$array:"), "$array:") == 0) {
146 int pos_idx = celltype.find_first_of(':');
147 int pos_num = celltype.find_first_of(':', pos_idx + 1);
148 int pos_type = celltype.find_first_of(':', pos_num + 1);
149 basicType = celltype.substr(pos_type + 1);
150 if (pos != nullptr) {
151 pos[0] = pos_idx;
152 pos[1] = pos_num;
153 pos[2] = pos_type;
154 }
155 }
156 return basicType;
157 }
158
159 // A helper struct for expanding a module's interface connections in expand_module
160 struct IFExpander
161 {
162 IFExpander (RTLIL::Design &design, RTLIL::Module &m)
163 : module(m), has_interfaces_not_found(false)
164 {
165 // Keep track of all derived interfaces available in the current
166 // module in 'interfaces_in_module':
167 for (auto cell : module.cells()) {
168 if(!cell->get_bool_attribute(ID::is_interface))
169 continue;
170
171 interfaces_in_module[cell->name] = design.module(cell->type);
172 }
173 }
174
175 RTLIL::Module &module;
176 dict<RTLIL::IdString, RTLIL::Module*> interfaces_in_module;
177
178 bool has_interfaces_not_found;
179 std::vector<RTLIL::IdString> connections_to_remove;
180 std::vector<RTLIL::IdString> connections_to_add_name;
181 std::vector<RTLIL::SigSpec> connections_to_add_signal;
182 dict<RTLIL::IdString, RTLIL::Module*> interfaces_to_add_to_submodule;
183 dict<RTLIL::IdString, RTLIL::IdString> modports_used_in_submodule;
184
185 // Reset the per-cell state
186 void start_cell()
187 {
188 has_interfaces_not_found = false;
189 connections_to_remove.clear();
190 connections_to_add_name.clear();
191 connections_to_add_signal.clear();
192 interfaces_to_add_to_submodule.clear();
193 modports_used_in_submodule.clear();
194 }
195
196 // Set has_interfaces_not_found if there are pending interfaces that
197 // haven't been found yet (and might be found in the future). Print a
198 // warning if we've already gone over all the cells in the module.
199 void on_missing_interface(RTLIL::IdString interface_name)
200 {
201 // If there are cells that haven't yet been processed, maybe
202 // we'll find this interface in the future.
203 if (module.get_bool_attribute(ID::cells_not_processed)) {
204 has_interfaces_not_found = true;
205 return;
206 }
207
208 // Otherwise, we have already gone over all cells in this
209 // module and the interface has still not been found. Warn
210 // about it and don't set has_interfaces_not_found (to avoid a
211 // loop).
212 log_warning("Could not find interface instance for `%s' in `%s'\n",
213 log_id(interface_name), log_id(&module));
214 }
215
216 // Handle an interface connection from the module
217 void on_interface(RTLIL::Module &submodule,
218 RTLIL::IdString conn_name,
219 const RTLIL::SigSpec &conn_signals)
220 {
221 // Check if the connected wire is a potential interface in the parent module
222 std::string interface_name_str = conn_signals.bits()[0].wire->name.str();
223 // Strip the prefix '$dummywireforinterface' from the dummy wire to get the name
224 interface_name_str.replace(0,23,"");
225 interface_name_str = "\\" + interface_name_str;
226 RTLIL::IdString interface_name = interface_name_str;
227
228 // If 'interfaces' in the cell have not be been handled yet, we aren't
229 // ready to derive the sub-module either
230 if (!module.get_bool_attribute(ID::interfaces_replaced_in_module)) {
231 on_missing_interface(interface_name);
232 return;
233 }
234
235 // Check if the interface instance is present in module. Interface
236 // instances may either have the plain name or the name appended with
237 // '_inst_from_top_dummy'. Check for both of them here
238 int nexactmatch = interfaces_in_module.count(interface_name) > 0;
239 std::string interface_name_str2 = interface_name_str + "_inst_from_top_dummy";
240 RTLIL::IdString interface_name2 = interface_name_str2;
241 int nmatch2 = interfaces_in_module.count(interface_name2) > 0;
242
243 // If we can't find either name, this is a missing interface.
244 if (! (nexactmatch || nmatch2)) {
245 on_missing_interface(interface_name);
246 return;
247 }
248
249 if (nexactmatch != 0) // Choose the one with the plain name if it exists
250 interface_name2 = interface_name;
251
252 RTLIL::Module *mod_replace_ports = interfaces_in_module.at(interface_name2);
253
254 // Go over all wires in interface, and add replacements to lists.
255 for (auto mod_wire : mod_replace_ports->wires()) {
256 std::string signal_name1 = conn_name.str() + "." + log_id(mod_wire->name);
257 std::string signal_name2 = interface_name.str() + "." + log_id(mod_wire);
258 connections_to_add_name.push_back(RTLIL::IdString(signal_name1));
259 if(module.wire(signal_name2) == nullptr) {
260 log_error("Could not find signal '%s' in '%s'\n",
261 signal_name2.c_str(), log_id(module.name));
262 }
263 else {
264 RTLIL::Wire *wire_in_parent = module.wire(signal_name2);
265 connections_to_add_signal.push_back(wire_in_parent);
266 }
267 }
268 connections_to_remove.push_back(conn_name);
269 interfaces_to_add_to_submodule[conn_name] = interfaces_in_module.at(interface_name2);
270
271 // Find if the sub-module has set a modport for the current interface
272 // connection. Add any modports to a dict which will be passed to
273 // AstModule::derive
274 string modport_name = submodule.wire(conn_name)->get_string_attribute(ID::interface_modport);
275 if (!modport_name.empty()) {
276 modports_used_in_submodule[conn_name] = "\\" + modport_name;
277 }
278 }
279
280 // Handle a single connection from the module, making a note to expand
281 // it if it's an interface connection.
282 void on_connection(RTLIL::Module &submodule,
283 RTLIL::IdString conn_name,
284 const RTLIL::SigSpec &conn_signals)
285 {
286 // Check if the connection is present as an interface in the sub-module's port list
287 const RTLIL::Wire *wire = submodule.wire(conn_name);
288 if (!wire || !wire->get_bool_attribute(ID::is_interface))
289 return;
290
291 // If the connection looks like an interface, handle it.
292 const auto &bits = conn_signals.bits();
293 if (bits.size() == 1 && bits[0].wire->get_bool_attribute(ID::is_interface))
294 on_interface(submodule, conn_name, conn_signals);
295 }
296
297 // Iterate over the connections in a cell, tracking any interface
298 // connections
299 void visit_connections(const RTLIL::Cell &cell,
300 RTLIL::Module &submodule)
301 {
302 for (const auto &conn : cell.connections()) {
303 on_connection(submodule, conn.first, conn.second);
304 }
305 }
306
307 // Add/remove connections to the cell as necessary, replacing any SV
308 // interface port connection with the individual signal connections.
309 void rewrite_interface_connections(RTLIL::Cell &cell) const
310 {
311 for(unsigned int i=0;i<connections_to_add_name.size();i++) {
312 cell.connections_[connections_to_add_name[i]] = connections_to_add_signal[i];
313 }
314 // Remove the connection for the interface itself:
315 for(unsigned int i=0;i<connections_to_remove.size();i++) {
316 cell.connections_.erase(connections_to_remove[i]);
317 }
318 }
319 };
320
321 // Get a module needed by a cell, either by deriving an abstract module or by
322 // loading one from a directory in libdirs.
323 //
324 // If the module can't be found and check is true then exit with an error
325 // message. Otherwise, return a pointer to the module if we derived or loaded
326 // something. or null otherwise (the module should be blackbox or we couldn't
327 // find it and check is not set).
328 RTLIL::Module *get_module(RTLIL::Design &design,
329 RTLIL::Cell &cell,
330 RTLIL::Module &parent,
331 bool check,
332 const std::vector<std::string> &libdirs)
333 {
334 std::string cell_type = cell.type.str();
335 RTLIL::Module *abs_mod = design.module("$abstract" + cell_type);
336 if (abs_mod) {
337 cell.type = abs_mod->derive(&design, cell.parameters);
338 cell.parameters.clear();
339 RTLIL::Module *mod = design.module(cell.type);
340 log_assert(mod);
341 return mod;
342 }
343
344 // If the cell type starts with '$' and isn't '$abstract', we should
345 // treat it as a black box and skip.
346 if (cell_type[0] == '$')
347 return nullptr;
348
349 for (auto &dir : libdirs) {
350 static const vector<pair<string, string>> extensions_list =
351 {
352 {".v", "verilog"},
353 {".sv", "verilog -sv"},
354 {".il", "rtlil"}
355 };
356
357 for (auto &ext : extensions_list) {
358 std::string filename = dir + "/" + RTLIL::unescape_id(cell.type) + ext.first;
359 if (!check_file_exists(filename))
360 continue;
361
362 Frontend::frontend_call(&design, NULL, filename, ext.second);
363 RTLIL::Module *mod = design.module(cell.type);
364 if (!mod)
365 log_error("File `%s' from libdir does not declare module `%s'.\n",
366 filename.c_str(), cell_type.c_str());
367 return mod;
368 }
369 }
370
371 // We couldn't find the module anywhere. Complain if check is set.
372 if (check)
373 log_error("Module `%s' referenced in module `%s' in cell `%s' is not part of the design.\n",
374 cell_type.c_str(), parent.name.c_str(), cell.name.c_str());
375
376 return nullptr;
377 }
378
379 // Try to read an IdString as a numbered connection name ("$123" or similar),
380 // writing the result to dst. If the string isn't of the right format, ignore
381 // dst and return false.
382 bool read_id_num(RTLIL::IdString str, int *dst)
383 {
384 log_assert(dst);
385
386 const char *c_str = str.c_str();
387 if (c_str[0] != '$' || !('0' <= c_str[1] && c_str[1] <= '9'))
388 return false;
389
390 *dst = atoi(c_str + 1);
391 return true;
392 }
393
394 // Check that the connections on the cell match those that are defined
395 // on the type: each named connection should match the name of a port
396 // and each positional connection should have an index smaller than
397 // the number of ports.
398 //
399 // Also do the same checks on the specified parameters.
400 void check_cell_connections(const RTLIL::Module &module, RTLIL::Cell &cell, RTLIL::Module &mod)
401 {
402 int id;
403 for (auto &conn : cell.connections()) {
404 if (read_id_num(conn.first, &id)) {
405 if (id <= 0 || id > GetSize(mod.ports))
406 log_error("Module `%s' referenced in module `%s' in cell `%s' "
407 "has only %d ports, requested port %d.\n",
408 log_id(cell.type), log_id(&module), log_id(&cell),
409 GetSize(mod.ports), id);
410 continue;
411 }
412
413 const RTLIL::Wire* wire = mod.wire(conn.first);
414 if (!wire || wire->port_id == 0) {
415 log_error("Module `%s' referenced in module `%s' in cell `%s' "
416 "does not have a port named '%s'.\n",
417 log_id(cell.type), log_id(&module), log_id(&cell),
418 log_id(conn.first));
419 }
420 }
421 for (auto &param : cell.parameters) {
422 if (read_id_num(param.first, &id)) {
423 if (id <= 0 || id > GetSize(mod.avail_parameters))
424 log_error("Module `%s' referenced in module `%s' in cell `%s' "
425 "has only %d parameters, requested parameter %d.\n",
426 log_id(cell.type), log_id(&module), log_id(&cell),
427 GetSize(mod.avail_parameters), id);
428 continue;
429 }
430
431 if (mod.avail_parameters.count(param.first) == 0 &&
432 param.first[0] != '$' &&
433 strchr(param.first.c_str(), '.') == NULL) {
434 log_error("Module `%s' referenced in module `%s' in cell `%s' "
435 "does not have a parameter named '%s'.\n",
436 log_id(cell.type), log_id(&module), log_id(&cell),
437 log_id(param.first));
438 }
439 }
440 }
441
442 bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs)
443 {
444 bool did_something = false;
445 std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
446 std::string filename;
447
448 bool has_interface_ports = false;
449
450 // If any of the ports are actually interface ports, we will always need to
451 // reprocess the module:
452 if(!module->get_bool_attribute(ID::interfaces_replaced_in_module)) {
453 for (auto wire : module->wires()) {
454 if ((wire->port_input || wire->port_output) && wire->get_bool_attribute(ID::is_interface))
455 has_interface_ports = true;
456 }
457 }
458
459 IFExpander if_expander(*design, *module);
460
461 for (auto cell : module->cells())
462 {
463 if_expander.start_cell();
464
465 if (cell->type.begins_with("$array:")) {
466 int pos[3];
467 basic_cell_type(cell->type.str(), pos);
468 int pos_idx = pos[0];
469 int pos_num = pos[1];
470 int pos_type = pos[2];
471 int idx = atoi(cell->type.substr(pos_idx + 1, pos_num).c_str());
472 int num = atoi(cell->type.substr(pos_num + 1, pos_type).c_str());
473 array_cells[cell] = std::pair<int, int>(idx, num);
474 cell->type = cell->type.substr(pos_type + 1);
475 }
476
477 RTLIL::Module *mod = design->module(cell->type);
478 if (!mod)
479 {
480 mod = get_module(*design, *cell, *module, flag_check || flag_simcheck, libdirs);
481
482 // If we still don't have a module, treat the cell as a black box and skip
483 // it. Otherwise, we either loaded or derived something so should set the
484 // did_something flag before returning (to ensure we come back and expand
485 // the thing we just loaded).
486 if (mod)
487 did_something = true;
488
489 continue;
490 }
491
492 log_assert(mod);
493
494 // Go over all connections and check if any of them are SV
495 // interfaces.
496 if_expander.visit_connections(*cell, *mod);
497
498 if (flag_check || flag_simcheck)
499 check_cell_connections(*module, *cell, *mod);
500
501 if (mod->get_blackbox_attribute()) {
502 if (flag_simcheck)
503 log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n",
504 cell->type.c_str(), module->name.c_str(), cell->name.c_str());
505 continue;
506 }
507
508 // If interface instances not yet found, skip cell for now, and say we did something, so that we will return back here:
509 if(if_expander.has_interfaces_not_found) {
510 did_something = true; // waiting for interfaces to be handled
511 continue;
512 }
513
514 if_expander.rewrite_interface_connections(*cell);
515
516 // If there are no overridden parameters AND not interfaces, then we can use the existing module instance as the type
517 // for the cell:
518 if (cell->parameters.size() == 0 &&
519 (if_expander.interfaces_to_add_to_submodule.size() == 0 ||
520 !(cell->get_bool_attribute(ID::module_not_derived)))) {
521 // If the cell being processed is an the interface instance itself, go down to "handle_interface_instance:",
522 // so that the signals of the interface are added to the parent module.
523 if (mod->get_bool_attribute(ID::is_interface)) {
524 goto handle_interface_instance;
525 }
526 continue;
527 }
528
529 cell->type = mod->derive(design,
530 cell->parameters,
531 if_expander.interfaces_to_add_to_submodule,
532 if_expander.modports_used_in_submodule);
533 cell->parameters.clear();
534 did_something = true;
535
536 handle_interface_instance:
537
538 // We add all the signals of the interface explicitly to the parent module. This is always needed when we encounter
539 // an interface instance:
540 if (mod->get_bool_attribute(ID::is_interface) && cell->get_bool_attribute(ID::module_not_derived)) {
541 cell->set_bool_attribute(ID::is_interface);
542 RTLIL::Module *derived_module = design->module(cell->type);
543 if_expander.interfaces_in_module[cell->name] = derived_module;
544 did_something = true;
545 }
546 // We clear 'module_not_derived' such that we will not rederive the cell again (needed when there are interfaces connected to the cell)
547 cell->attributes.erase(ID::module_not_derived);
548 }
549 // Clear the attribute 'cells_not_processed' such that it can be known that we
550 // have been through all cells at least once, and that we can know whether
551 // to flag an error because of interface instances not found:
552 module->attributes.erase(ID::cells_not_processed);
553
554
555 // If any interface instances or interface ports were found in the module, we need to rederive it completely:
556 if ((if_expander.interfaces_in_module.size() > 0 || has_interface_ports) && !module->get_bool_attribute(ID::interfaces_replaced_in_module)) {
557 module->expand_interfaces(design, if_expander.interfaces_in_module);
558 return did_something;
559 }
560
561 // Now that modules have been derived, we may want to reprocess this
562 // module given the additional available context.
563 if (module->reprocess_if_necessary(design))
564 return true;
565
566 for (auto &it : array_cells)
567 {
568 RTLIL::Cell *cell = it.first;
569 int idx = it.second.first, num = it.second.second;
570
571 if (design->module(cell->type) == nullptr)
572 log_error("Array cell `%s.%s' of unknown type `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
573
574 RTLIL::Module *mod = design->module(cell->type);
575
576 for (auto &conn : cell->connections_) {
577 int conn_size = conn.second.size();
578 RTLIL::IdString portname = conn.first;
579 if (portname.begins_with("$")) {
580 int port_id = atoi(portname.substr(1).c_str());
581 for (auto wire : mod->wires())
582 if (wire->port_id == port_id) {
583 portname = wire->name;
584 break;
585 }
586 }
587 if (mod->wire(portname) == nullptr)
588 log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
589 int port_size = mod->wire(portname)->width;
590 if (conn_size == port_size || conn_size == 0)
591 continue;
592 if (conn_size != port_size*num)
593 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));
594 conn.second = conn.second.extract(port_size*idx, port_size);
595 }
596 }
597
598 return did_something;
599 }
600
601 void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> &used, RTLIL::Module *mod, int indent)
602 {
603 if (used.count(mod) > 0)
604 return;
605
606 if (indent == 0)
607 log("Top module: %s\n", mod->name.c_str());
608 else if (!mod->get_blackbox_attribute())
609 log("Used module: %*s%s\n", indent, "", mod->name.c_str());
610 used.insert(mod);
611
612 for (auto cell : mod->cells()) {
613 std::string celltype = cell->type.str();
614 if (celltype.compare(0, strlen("$array:"), "$array:") == 0)
615 celltype = basic_cell_type(celltype);
616 if (design->module(celltype))
617 hierarchy_worker(design, used, design->module(celltype), indent+4);
618 }
619 }
620
621 void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
622 {
623 std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used;
624 hierarchy_worker(design, used, top, 0);
625
626 std::vector<RTLIL::Module*> del_modules;
627 for (auto mod : design->modules())
628 if (used.count(mod) == 0)
629 del_modules.push_back(mod);
630 else {
631 // Now all interface ports must have been exploded, and it is hence
632 // safe to delete all of the remaining dummy interface ports:
633 pool<RTLIL::Wire*> del_wires;
634 for(auto wire : mod->wires()) {
635 if ((wire->port_input || wire->port_output) && wire->get_bool_attribute(ID::is_interface)) {
636 del_wires.insert(wire);
637 }
638 }
639 if (del_wires.size() > 0) {
640 mod->remove(del_wires);
641 mod->fixup_ports();
642 }
643 }
644
645 int del_counter = 0;
646 for (auto mod : del_modules) {
647 if (!purge_lib && mod->get_blackbox_attribute())
648 continue;
649 log("Removing unused module `%s'.\n", mod->name.c_str());
650 design->remove(mod);
651 del_counter++;
652 }
653
654 log("Removed %d unused modules.\n", del_counter);
655 }
656
657 bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
658 {
659 if (cache.count(mod) == 0)
660 for (auto c : mod->cells()) {
661 RTLIL::Module *m = mod->design->module(c->type);
662 if ((m != nullptr && set_keep_assert(cache, m)) || c->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover)))
663 return cache[mod] = true;
664 }
665 return cache[mod];
666 }
667
668 int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
669 {
670 if (db.count(module) == 0) {
671 int score = 0;
672 db[module] = 0;
673 for (auto cell : module->cells()) {
674 std::string celltype = cell->type.str();
675 // Is this an array instance
676 if (celltype.compare(0, strlen("$array:"), "$array:") == 0)
677 celltype = basic_cell_type(celltype);
678 // Is this cell a module instance?
679 auto instModule = design->module(celltype);
680 // If there is no instance for this, issue a warning.
681 if (instModule != nullptr) {
682 score = max(score, find_top_mod_score(design, instModule, db) + 1);
683 }
684 }
685 db[module] = score;
686 }
687 return db.at(module);
688 }
689
690 RTLIL::Module *check_if_top_has_changed(Design *design, Module *top_mod)
691 {
692 if(top_mod != NULL && top_mod->get_bool_attribute(ID::initial_top))
693 return top_mod;
694 else {
695 for (auto mod : design->modules()) {
696 if (mod->get_bool_attribute(ID::top)) {
697 return mod;
698 }
699 }
700 }
701 return NULL;
702 }
703
704 // Find a matching wire for an implicit port connection; traversing generate block scope
705 RTLIL::Wire *find_implicit_port_wire(Module *module, Cell *cell, const std::string& port)
706 {
707 const std::string &cellname = cell->name.str();
708 size_t idx = cellname.size();
709 while ((idx = cellname.find_last_of('.', idx-1)) != std::string::npos) {
710 Wire *found = module->wire(cellname.substr(0, idx+1) + port.substr(1));
711 if (found != nullptr)
712 return found;
713 }
714 return module->wire(port);
715 }
716
717 struct HierarchyPass : public Pass {
718 HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
719 void help() override
720 {
721 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
722 log("\n");
723 log(" hierarchy [-check] [-top <module>]\n");
724 log(" hierarchy -generate <cell-types> <port-decls>\n");
725 log("\n");
726 log("In parametric designs, a module might exists in several variations with\n");
727 log("different parameter values. This pass looks at all modules in the current\n");
728 log("design and re-runs the language frontends for the parametric modules as\n");
729 log("needed. It also resolves assignments to wired logic data types (wand/wor),\n");
730 log("resolves positional module parameters, unrolls array instances, and more.\n");
731 log("\n");
732 log(" -check\n");
733 log(" also check the design hierarchy. this generates an error when\n");
734 log(" an unknown module is used as cell type.\n");
735 log("\n");
736 log(" -simcheck\n");
737 log(" like -check, but also throw an error if blackbox modules are\n");
738 log(" instantiated, and throw an error if the design has no top module.\n");
739 log("\n");
740 log(" -purge_lib\n");
741 log(" by default the hierarchy command will not remove library (blackbox)\n");
742 log(" modules. use this option to also remove unused blackbox modules.\n");
743 log("\n");
744 log(" -libdir <directory>\n");
745 log(" search for files named <module_name>.v in the specified directory\n");
746 log(" for unknown modules and automatically run read_verilog for each\n");
747 log(" unknown module.\n");
748 log("\n");
749 log(" -keep_positionals\n");
750 log(" per default this pass also converts positional arguments in cells\n");
751 log(" to arguments using port names. This option disables this behavior.\n");
752 log("\n");
753 log(" -keep_portwidths\n");
754 log(" per default this pass adjusts the port width on cells that are\n");
755 log(" module instances when the width does not match the module port. This\n");
756 log(" option disables this behavior.\n");
757 log("\n");
758 log(" -nodefaults\n");
759 log(" do not resolve input port default values\n");
760 log("\n");
761 log(" -nokeep_asserts\n");
762 log(" per default this pass sets the \"keep\" attribute on all modules\n");
763 log(" that directly or indirectly contain one or more formal properties.\n");
764 log(" This option disables this behavior.\n");
765 log("\n");
766 log(" -top <module>\n");
767 log(" use the specified top module to build the design hierarchy. Modules\n");
768 log(" outside this tree (unused modules) are removed.\n");
769 log("\n");
770 log(" when the -top option is used, the 'top' attribute will be set on the\n");
771 log(" specified top module. otherwise a module with the 'top' attribute set\n");
772 log(" will implicitly be used as top module, if such a module exists.\n");
773 log("\n");
774 log(" -auto-top\n");
775 log(" automatically determine the top of the design hierarchy and mark it.\n");
776 log("\n");
777 log(" -chparam name value \n");
778 log(" elaborate the top module using this parameter value. Modules on which\n");
779 log(" this parameter does not exist may cause a warning message to be output.\n");
780 log(" This option can be specified multiple times to override multiple\n");
781 log(" parameters. String values must be passed in double quotes (\").\n");
782 log("\n");
783 log("In -generate mode this pass generates blackbox modules for the given cell\n");
784 log("types (wildcards supported). For this the design is searched for cells that\n");
785 log("match the given types and then the given port declarations are used to\n");
786 log("determine the direction of the ports. The syntax for a port declaration is:\n");
787 log("\n");
788 log(" {i|o|io}[@<num>]:<portname>\n");
789 log("\n");
790 log("Input ports are specified with the 'i' prefix, output ports with the 'o'\n");
791 log("prefix and inout ports with the 'io' prefix. The optional <num> specifies\n");
792 log("the position of the port in the parameter list (needed when instantiated\n");
793 log("using positional arguments). When <num> is not specified, the <portname> can\n");
794 log("also contain wildcard characters.\n");
795 log("\n");
796 log("This pass ignores the current selection and always operates on all modules\n");
797 log("in the current design.\n");
798 log("\n");
799 }
800 void execute(std::vector<std::string> args, RTLIL::Design *design) override
801 {
802 log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n");
803
804 bool flag_check = false;
805 bool flag_simcheck = false;
806 bool purge_lib = false;
807 RTLIL::Module *top_mod = NULL;
808 std::string load_top_mod;
809 std::vector<std::string> libdirs;
810
811 bool auto_top_mode = false;
812 bool generate_mode = false;
813 bool keep_positionals = false;
814 bool keep_portwidths = false;
815 bool nodefaults = false;
816 bool nokeep_asserts = false;
817 std::vector<std::string> generate_cells;
818 std::vector<generate_port_decl_t> generate_ports;
819 std::map<std::string, std::string> parameters;
820
821 size_t argidx;
822 for (argidx = 1; argidx < args.size(); argidx++)
823 {
824 if (args[argidx] == "-generate" && !flag_check && !flag_simcheck && !top_mod) {
825 generate_mode = true;
826 log("Entering generate mode.\n");
827 while (++argidx < args.size()) {
828 const char *p = args[argidx].c_str();
829 generate_port_decl_t decl;
830 if (p[0] == 'i' && p[1] == 'o')
831 decl.input = true, decl.output = true, p += 2;
832 else if (*p == 'i')
833 decl.input = true, decl.output = false, p++;
834 else if (*p == 'o')
835 decl.input = false, decl.output = true, p++;
836 else
837 goto is_celltype;
838 if (*p == '@') {
839 char *endptr;
840 decl.index = strtol(++p, &endptr, 10);
841 if (decl.index < 1)
842 goto is_celltype;
843 p = endptr;
844 } else
845 decl.index = 0;
846 if (*(p++) != ':')
847 goto is_celltype;
848 if (*p == 0)
849 goto is_celltype;
850 decl.portname = p;
851 log("Port declaration: %s", decl.input ? decl.output ? "inout" : "input" : "output");
852 if (decl.index >= 1)
853 log(" [at position %d]", decl.index);
854 log(" %s\n", decl.portname.c_str());
855 generate_ports.push_back(decl);
856 continue;
857 is_celltype:
858 log("Celltype: %s\n", args[argidx].c_str());
859 generate_cells.push_back(RTLIL::unescape_id(args[argidx]));
860 }
861 continue;
862 }
863 if (args[argidx] == "-check") {
864 flag_check = true;
865 continue;
866 }
867 if (args[argidx] == "-simcheck") {
868 flag_simcheck = true;
869 continue;
870 }
871 if (args[argidx] == "-purge_lib") {
872 purge_lib = true;
873 continue;
874 }
875 if (args[argidx] == "-keep_positionals") {
876 keep_positionals = true;
877 continue;
878 }
879 if (args[argidx] == "-keep_portwidths") {
880 keep_portwidths = true;
881 continue;
882 }
883 if (args[argidx] == "-nodefaults") {
884 nodefaults = true;
885 continue;
886 }
887 if (args[argidx] == "-nokeep_asserts") {
888 nokeep_asserts = true;
889 continue;
890 }
891 if (args[argidx] == "-libdir" && argidx+1 < args.size()) {
892 libdirs.push_back(args[++argidx]);
893 continue;
894 }
895 if (args[argidx] == "-top") {
896 if (++argidx >= args.size())
897 log_cmd_error("Option -top requires an additional argument!\n");
898 load_top_mod = args[argidx];
899 continue;
900 }
901 if (args[argidx] == "-auto-top") {
902 auto_top_mode = true;
903 continue;
904 }
905 if (args[argidx] == "-chparam" && argidx+2 < args.size()) {
906 const std::string &key = args[++argidx];
907 const std::string &value = args[++argidx];
908 auto r = parameters.emplace(key, value);
909 if (!r.second) {
910 log_warning("-chparam %s already specified: overwriting.\n", key.c_str());
911 r.first->second = value;
912 }
913 continue;
914 }
915 break;
916 }
917 extra_args(args, argidx, design, false);
918
919 if (!load_top_mod.empty())
920 {
921 IdString top_name = RTLIL::escape_id(load_top_mod);
922 IdString abstract_id = "$abstract" + RTLIL::escape_id(load_top_mod);
923 top_mod = design->module(top_name);
924
925 dict<RTLIL::IdString, RTLIL::Const> top_parameters;
926 if ((top_mod == nullptr && design->module(abstract_id)) || top_mod != nullptr) {
927 for (auto &para : parameters) {
928 SigSpec sig_value;
929 if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second))
930 log_cmd_error("Can't decode value '%s'!\n", para.second.c_str());
931 top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
932 }
933 }
934
935 if (top_mod == nullptr && design->module(abstract_id))
936 top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters));
937 else if (top_mod != nullptr && !top_parameters.empty())
938 top_mod = design->module(top_mod->derive(design, top_parameters));
939
940 if (top_mod != nullptr && top_mod->name != top_name) {
941 Module *m = top_mod->clone();
942 m->name = top_name;
943 Module *old_mod = design->module(top_name);
944 if (old_mod)
945 design->remove(old_mod);
946 design->add(m);
947 top_mod = m;
948 }
949 }
950
951 if (top_mod == nullptr && !load_top_mod.empty()) {
952 #ifdef YOSYS_ENABLE_VERIFIC
953 if (verific_import_pending) {
954 verific_import(design, parameters, load_top_mod);
955 top_mod = design->module(RTLIL::escape_id(load_top_mod));
956 }
957 #endif
958 if (top_mod == NULL)
959 log_cmd_error("Module `%s' not found!\n", load_top_mod.c_str());
960 } else {
961 #ifdef YOSYS_ENABLE_VERIFIC
962 if (verific_import_pending)
963 verific_import(design, parameters);
964 #endif
965 }
966
967 if (generate_mode) {
968 generate(design, generate_cells, generate_ports);
969 return;
970 }
971
972 log_push();
973
974 if (top_mod == nullptr)
975 for (auto mod : design->modules())
976 if (mod->get_bool_attribute(ID::top))
977 top_mod = mod;
978
979 if (top_mod == nullptr && auto_top_mode) {
980 log_header(design, "Finding top of design hierarchy..\n");
981 dict<Module*, int> db;
982 for (Module *mod : design->selected_modules()) {
983 int score = find_top_mod_score(design, mod, db);
984 log("root of %3d design levels: %-20s\n", score, log_id(mod));
985 if (!top_mod || score > db[top_mod])
986 top_mod = mod;
987 }
988 if (top_mod != nullptr)
989 log("Automatically selected %s as design top module.\n", log_id(top_mod));
990 }
991
992 if (top_mod != nullptr && top_mod->name.begins_with("$abstract")) {
993 IdString top_name = top_mod->name.substr(strlen("$abstract"));
994
995 dict<RTLIL::IdString, RTLIL::Const> top_parameters;
996 for (auto &para : parameters) {
997 SigSpec sig_value;
998 if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second))
999 log_cmd_error("Can't decode value '%s'!\n", para.second.c_str());
1000 top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
1001 }
1002
1003 top_mod = design->module(top_mod->derive(design, top_parameters));
1004
1005 if (top_mod != nullptr && top_mod->name != top_name) {
1006 Module *m = top_mod->clone();
1007 m->name = top_name;
1008 Module *old_mod = design->module(top_name);
1009 if (old_mod)
1010 design->remove(old_mod);
1011 design->add(m);
1012 top_mod = m;
1013 }
1014 }
1015
1016 if (flag_simcheck && top_mod == nullptr)
1017 log_error("Design has no top module.\n");
1018
1019 if (top_mod != NULL) {
1020 for (auto mod : design->modules())
1021 if (mod == top_mod)
1022 mod->attributes[ID::initial_top] = RTLIL::Const(1);
1023 else
1024 mod->attributes.erase(ID::initial_top);
1025 }
1026
1027 bool did_something = true;
1028 while (did_something)
1029 {
1030 did_something = false;
1031
1032 std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used_modules;
1033 if (top_mod != NULL) {
1034 log_header(design, "Analyzing design hierarchy..\n");
1035 hierarchy_worker(design, used_modules, top_mod, 0);
1036 } else {
1037 for (auto mod : design->modules())
1038 used_modules.insert(mod);
1039 }
1040
1041 for (auto module : used_modules) {
1042 if (expand_module(design, module, flag_check, flag_simcheck, libdirs))
1043 did_something = true;
1044 }
1045
1046
1047 // The top module might have changed if interface instances have been detected in it:
1048 RTLIL::Module *tmp_top_mod = check_if_top_has_changed(design, top_mod);
1049 if (tmp_top_mod != NULL) {
1050 if (tmp_top_mod != top_mod){
1051 top_mod = tmp_top_mod;
1052 did_something = true;
1053 }
1054 }
1055
1056 // Delete modules marked as 'to_delete':
1057 std::vector<RTLIL::Module *> modules_to_delete;
1058 for(auto mod : design->modules()) {
1059 if (mod->get_bool_attribute(ID::to_delete)) {
1060 modules_to_delete.push_back(mod);
1061 }
1062 }
1063 for(size_t i=0; i<modules_to_delete.size(); i++) {
1064 design->remove(modules_to_delete[i]);
1065 }
1066 }
1067
1068
1069 if (top_mod != NULL) {
1070 log_header(design, "Analyzing design hierarchy..\n");
1071 hierarchy_clean(design, top_mod, purge_lib);
1072 }
1073
1074 if (top_mod != NULL) {
1075 for (auto mod : design->modules()) {
1076 if (mod == top_mod)
1077 mod->attributes[ID::top] = RTLIL::Const(1);
1078 else
1079 mod->attributes.erase(ID::top);
1080 mod->attributes.erase(ID::initial_top);
1081 }
1082 }
1083
1084 if (!nokeep_asserts) {
1085 std::map<RTLIL::Module*, bool> cache;
1086 for (auto mod : design->modules())
1087 if (set_keep_assert(cache, mod)) {
1088 log("Module %s directly or indirectly contains formal properties -> setting \"keep\" attribute.\n", log_id(mod));
1089 mod->set_bool_attribute(ID::keep);
1090 }
1091 }
1092
1093 if (!keep_positionals)
1094 {
1095 std::set<RTLIL::Module*> pos_mods;
1096 std::map<std::pair<RTLIL::Module*,int>, RTLIL::IdString> pos_map;
1097 std::vector<std::pair<RTLIL::Module*,RTLIL::Cell*>> pos_work;
1098
1099 for (auto mod : design->modules())
1100 for (auto cell : mod->cells()) {
1101 RTLIL::Module *cell_mod = design->module(cell->type);
1102 if (cell_mod == nullptr)
1103 continue;
1104 for (auto &conn : cell->connections())
1105 if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
1106 pos_mods.insert(design->module(cell->type));
1107 pos_work.push_back(std::pair<RTLIL::Module*,RTLIL::Cell*>(mod, cell));
1108 break;
1109 }
1110
1111 pool<std::pair<IdString, IdString>> params_rename;
1112 for (const auto &p : cell->parameters) {
1113 int id;
1114 if (read_id_num(p.first, &id)) {
1115 if (id <= 0 || id > GetSize(cell_mod->avail_parameters)) {
1116 log(" Failed to map positional parameter %d of cell %s.%s (%s).\n",
1117 id, RTLIL::id2cstr(mod->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
1118 } else {
1119 params_rename.insert(std::make_pair(p.first, cell_mod->avail_parameters[id - 1]));
1120 }
1121 }
1122 }
1123 for (const auto &p : params_rename) {
1124 cell->setParam(p.second, cell->getParam(p.first));
1125 cell->unsetParam(p.first);
1126 }
1127 }
1128
1129 for (auto module : pos_mods)
1130 for (auto wire : module->wires()) {
1131 if (wire->port_id > 0)
1132 pos_map[std::pair<RTLIL::Module*,int>(module, wire->port_id)] = wire->name;
1133 }
1134
1135 for (auto &work : pos_work) {
1136 RTLIL::Module *module = work.first;
1137 RTLIL::Cell *cell = work.second;
1138 log("Mapping positional arguments of cell %s.%s (%s).\n",
1139 RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
1140 dict<RTLIL::IdString, RTLIL::SigSpec> new_connections;
1141 for (auto &conn : cell->connections()) {
1142 int id;
1143 if (read_id_num(conn.first, &id)) {
1144 std::pair<RTLIL::Module*,int> key(design->module(cell->type), id);
1145 if (pos_map.count(key) == 0) {
1146 log(" Failed to map positional argument %d of cell %s.%s (%s).\n",
1147 id, RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
1148 new_connections[conn.first] = conn.second;
1149 } else
1150 new_connections[pos_map.at(key)] = conn.second;
1151 } else
1152 new_connections[conn.first] = conn.second;
1153 }
1154 cell->connections_ = new_connections;
1155 }
1156 }
1157
1158 // Determine default values
1159 dict<IdString, dict<IdString, Const>> defaults_db;
1160 if (!nodefaults)
1161 {
1162 for (auto module : design->modules())
1163 for (auto wire : module->wires())
1164 if (wire->port_input && wire->attributes.count(ID::defaultvalue))
1165 defaults_db[module->name][wire->name] = wire->attributes.at(ID::defaultvalue);
1166 }
1167 // Process SV implicit wildcard port connections
1168 std::set<Module*> blackbox_derivatives;
1169 std::vector<Module*> design_modules = design->modules();
1170
1171 for (auto module : design_modules)
1172 {
1173 for (auto cell : module->cells())
1174 {
1175 if (!cell->get_bool_attribute(ID::wildcard_port_conns))
1176 continue;
1177 Module *m = design->module(cell->type);
1178
1179 if (m == nullptr)
1180 log_error("Cell %s.%s (%s) has implicit port connections but the module it instantiates is unknown.\n",
1181 RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
1182
1183 // Need accurate port widths for error checking; so must derive blackboxes with dynamic port widths
1184 if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute(ID::dynports)) {
1185 IdString new_m_name = m->derive(design, cell->parameters, true);
1186 if (new_m_name.empty())
1187 continue;
1188 if (new_m_name != m->name) {
1189 m = design->module(new_m_name);
1190 blackbox_derivatives.insert(m);
1191 }
1192 }
1193
1194 auto old_connections = cell->connections();
1195 for (auto wire : m->wires()) {
1196 // Find ports of the module that aren't explicitly connected
1197 if (!wire->port_input && !wire->port_output)
1198 continue;
1199 if (old_connections.count(wire->name))
1200 continue;
1201 // Make sure a wire of correct name exists in the parent
1202 Wire* parent_wire = find_implicit_port_wire(module, cell, wire->name.str());
1203
1204 // Missing wires are OK when a default value is set
1205 if (!nodefaults && parent_wire == nullptr && defaults_db.count(cell->type) && defaults_db.at(cell->type).count(wire->name))
1206 continue;
1207
1208 if (parent_wire == nullptr)
1209 log_error("No matching wire for implicit port connection `%s' of cell %s.%s (%s).\n",
1210 RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
1211 if (parent_wire->width != wire->width)
1212 log_error("Width mismatch between wire (%d bits) and port (%d bits) for implicit port connection `%s' of cell %s.%s (%s).\n",
1213 parent_wire->width, wire->width,
1214 RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
1215 cell->setPort(wire->name, parent_wire);
1216 }
1217 cell->attributes.erase(ID::wildcard_port_conns);
1218 }
1219 }
1220
1221 if (!nodefaults)
1222 {
1223 for (auto module : design->modules())
1224 for (auto cell : module->cells())
1225 {
1226 if (defaults_db.count(cell->type) == 0)
1227 continue;
1228
1229 if (keep_positionals) {
1230 bool found_positionals = false;
1231 for (auto &conn : cell->connections())
1232 if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9')
1233 found_positionals = true;
1234 if (found_positionals)
1235 continue;
1236 }
1237
1238 for (auto &it : defaults_db.at(cell->type))
1239 if (!cell->hasPort(it.first))
1240 cell->setPort(it.first, it.second);
1241 }
1242 }
1243
1244 for (auto module : design_modules)
1245 {
1246 pool<Wire*> wand_wor_index;
1247 dict<Wire*, SigSpec> wand_map, wor_map;
1248 vector<SigSig> new_connections;
1249
1250 for (auto wire : module->wires())
1251 {
1252 if (wire->get_bool_attribute(ID::wand)) {
1253 wand_map[wire] = SigSpec();
1254 wand_wor_index.insert(wire);
1255 }
1256 if (wire->get_bool_attribute(ID::wor)) {
1257 wor_map[wire] = SigSpec();
1258 wand_wor_index.insert(wire);
1259 }
1260 }
1261
1262 for (auto &conn : module->connections())
1263 {
1264 SigSig new_conn;
1265 int cursor = 0;
1266
1267 for (auto c : conn.first.chunks())
1268 {
1269 Wire *w = c.wire;
1270 SigSpec rhs = conn.second.extract(cursor, GetSize(c));
1271
1272 if (wand_wor_index.count(w) == 0) {
1273 new_conn.first.append(c);
1274 new_conn.second.append(rhs);
1275 } else {
1276 if (wand_map.count(w)) {
1277 SigSpec sig = SigSpec(State::S1, GetSize(w));
1278 sig.replace(c.offset, rhs);
1279 wand_map.at(w).append(sig);
1280 } else {
1281 SigSpec sig = SigSpec(State::S0, GetSize(w));
1282 sig.replace(c.offset, rhs);
1283 wor_map.at(w).append(sig);
1284 }
1285 }
1286 cursor += GetSize(c);
1287 }
1288 new_connections.push_back(new_conn);
1289 }
1290 module->new_connections(new_connections);
1291
1292 for (auto cell : module->cells())
1293 {
1294 if (!cell->known())
1295 continue;
1296
1297 for (auto &conn : cell->connections())
1298 {
1299 if (!cell->output(conn.first))
1300 continue;
1301
1302 SigSpec new_sig;
1303 bool update_port = false;
1304
1305 for (auto c : conn.second.chunks())
1306 {
1307 Wire *w = c.wire;
1308
1309 if (wand_wor_index.count(w) == 0) {
1310 new_sig.append(c);
1311 continue;
1312 }
1313
1314 Wire *t = module->addWire(NEW_ID, GetSize(c));
1315 new_sig.append(t);
1316 update_port = true;
1317
1318 if (wand_map.count(w)) {
1319 SigSpec sig = SigSpec(State::S1, GetSize(w));
1320 sig.replace(c.offset, t);
1321 wand_map.at(w).append(sig);
1322 } else {
1323 SigSpec sig = SigSpec(State::S0, GetSize(w));
1324 sig.replace(c.offset, t);
1325 wor_map.at(w).append(sig);
1326 }
1327 }
1328
1329 if (update_port)
1330 cell->setPort(conn.first, new_sig);
1331 }
1332 }
1333
1334 for (auto w : wand_wor_index)
1335 {
1336 bool wand = wand_map.count(w);
1337 SigSpec sigs = wand ? wand_map.at(w) : wor_map.at(w);
1338
1339 if (GetSize(sigs) == 0)
1340 continue;
1341
1342 if (GetSize(w) == 1) {
1343 if (wand)
1344 module->addReduceAnd(NEW_ID, sigs, w);
1345 else
1346 module->addReduceOr(NEW_ID, sigs, w);
1347 continue;
1348 }
1349
1350 SigSpec s = sigs.extract(0, GetSize(w));
1351 for (int i = GetSize(w); i < GetSize(sigs); i += GetSize(w)) {
1352 if (wand)
1353 s = module->And(NEW_ID, s, sigs.extract(i, GetSize(w)));
1354 else
1355 s = module->Or(NEW_ID, s, sigs.extract(i, GetSize(w)));
1356 }
1357 module->connect(w, s);
1358 }
1359
1360 for (auto cell : module->cells())
1361 {
1362 Module *m = design->module(cell->type);
1363
1364 if (m == nullptr)
1365 continue;
1366
1367 if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute(ID::dynports)) {
1368 IdString new_m_name = m->derive(design, cell->parameters, true);
1369 if (new_m_name.empty())
1370 continue;
1371 if (new_m_name != m->name) {
1372 m = design->module(new_m_name);
1373 blackbox_derivatives.insert(m);
1374 }
1375 }
1376
1377 for (auto &conn : cell->connections())
1378 {
1379 Wire *w = m->wire(conn.first);
1380
1381 if (w == nullptr || w->port_id == 0)
1382 continue;
1383
1384 if (GetSize(conn.second) == 0)
1385 continue;
1386
1387 SigSpec sig = conn.second;
1388
1389 if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
1390 {
1391 if (GetSize(w) < GetSize(conn.second))
1392 {
1393 int n = GetSize(conn.second) - GetSize(w);
1394 if (!w->port_input && w->port_output)
1395 {
1396 RTLIL::SigSpec out = sig.extract(0, GetSize(w));
1397 out.extend_u0(GetSize(sig), w->is_signed);
1398 module->connect(sig.extract(GetSize(w), n), out.extract(GetSize(w), n));
1399 }
1400 sig.remove(GetSize(w), n);
1401 }
1402 else
1403 {
1404 int n = GetSize(w) - GetSize(conn.second);
1405 if (w->port_input && !w->port_output)
1406 sig.extend_u0(GetSize(w), sig.is_wire() && sig.as_wire()->is_signed);
1407 else
1408 sig.append(module->addWire(NEW_ID, n));
1409 }
1410
1411 if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
1412 log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
1413 log_id(conn.first), GetSize(conn.second), GetSize(sig));
1414 cell->setPort(conn.first, sig);
1415 }
1416
1417 if (w->port_output && !w->port_input && sig.has_const())
1418 log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
1419 log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
1420 }
1421 }
1422 }
1423
1424 for (auto module : blackbox_derivatives)
1425 design->remove(module);
1426
1427 log_pop();
1428 }
1429 } HierarchyPass;
1430
1431 PRIVATE_NAMESPACE_END