2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
5 * Copyright (C) 2018 Ruben Undheim <ruben.undheim@gmail.com>
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.
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.
21 #include "kernel/yosys.h"
22 #include "frontends/verific/verific.h"
33 PRIVATE_NAMESPACE_BEGIN
35 struct generate_port_decl_t
{
41 void generate(RTLIL::Design
*design
, const std::vector
<std::string
> &celltypes
, const std::vector
<generate_port_decl_t
> &portdecls
)
43 std::set
<RTLIL::IdString
> found_celltypes
;
45 for (auto mod
: design
->modules())
46 for (auto cell
: mod
->cells())
48 if (design
->module(cell
->type
) != nullptr)
50 if (cell
->type
.begins_with("$__"))
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 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());
72 for (auto ¶
: cell
->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
[ID::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 // 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) {
159 // A helper struct for expanding a module's interface connections in expand_module
162 IFExpander (RTLIL::Design
&design
, RTLIL::Module
&m
)
163 : module(m
), has_interfaces_not_found(false)
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
))
171 interfaces_in_module
[cell
->name
] = design
.module(cell
->type
);
175 RTLIL::Module
&module
;
176 dict
<RTLIL::IdString
, RTLIL::Module
*> interfaces_in_module
;
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
;
185 // Reset the per-cell state
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();
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
)
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;
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
212 log_warning("Could not find interface instance for `%s' in `%s'\n",
213 log_id(interface_name
), log_id(&module
));
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
)
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
;
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
);
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;
243 // If we can't find either name, this is a missing interface.
244 if (! (nexactmatch
|| nmatch2
)) {
245 on_missing_interface(interface_name
);
249 if (nexactmatch
!= 0) // Choose the one with the plain name if it exists
250 interface_name2
= interface_name
;
252 RTLIL::Module
*mod_replace_ports
= interfaces_in_module
.at(interface_name2
);
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
));
264 RTLIL::Wire
*wire_in_parent
= module
.wire(signal_name2
);
265 connections_to_add_signal
.push_back(wire_in_parent
);
268 connections_to_remove
.push_back(conn_name
);
269 interfaces_to_add_to_submodule
[conn_name
] = interfaces_in_module
.at(interface_name2
);
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
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
;
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
)
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
))
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
);
297 // Iterate over the connections in a cell, tracking any interface
299 void visit_connections(const RTLIL::Cell
&cell
,
300 RTLIL::Module
&submodule
)
302 for (const auto &conn
: cell
.connections()) {
303 on_connection(submodule
, conn
.first
, conn
.second
);
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
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
];
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
]);
321 // Get a module needed by a cell, either by deriving an abstract module or by
322 // loading one from a directory in libdirs.
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
,
330 RTLIL::Module
&parent
,
332 const std::vector
<std::string
> &libdirs
)
334 std::string cell_type
= cell
.type
.str();
335 RTLIL::Module
*abs_mod
= design
.module("$abstract" + cell_type
);
337 cell
.type
= abs_mod
->derive(&design
, cell
.parameters
);
338 cell
.parameters
.clear();
339 RTLIL::Module
*mod
= design
.module(cell
.type
);
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] == '$')
349 for (auto &dir
: libdirs
) {
350 static const vector
<pair
<string
, string
>> extensions_list
=
353 {".sv", "verilog -sv"},
357 for (auto &ext
: extensions_list
) {
358 std::string filename
= dir
+ "/" + RTLIL::unescape_id(cell
.type
) + ext
.first
;
359 if (!check_file_exists(filename
))
362 Frontend::frontend_call(&design
, NULL
, filename
, ext
.second
);
363 RTLIL::Module
*mod
= design
.module(cell
.type
);
365 log_error("File `%s' from libdir does not declare module `%s'.\n",
366 filename
.c_str(), cell_type
.c_str());
371 // We couldn't find the module anywhere. Complain if check is set.
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());
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
)
386 const char *c_str
= str
.c_str();
387 if (c_str
[0] != '$' || !('0' <= c_str
[1] && c_str
[1] <= '9'))
390 *dst
= atoi(c_str
+ 1);
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.
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
)
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
);
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
),
421 for (auto ¶m
: 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
);
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
));
442 bool expand_module(RTLIL::Design
*design
, RTLIL::Module
*module
, bool flag_check
, bool flag_simcheck
, std::vector
<std::string
> &libdirs
)
444 bool did_something
= false;
445 std::map
<RTLIL::Cell
*, std::pair
<int, int>> array_cells
;
446 std::string filename
;
448 bool has_interface_ports
= false;
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;
459 IFExpander
if_expander(*design
, *module
);
461 for (auto cell
: module
->cells())
463 if_expander
.start_cell();
465 if (cell
->type
.begins_with("$array:")) {
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);
477 RTLIL::Module
*mod
= design
->module(cell
->type
);
480 mod
= get_module(*design
, *cell
, *module
, flag_check
|| flag_simcheck
, libdirs
);
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).
487 did_something
= true;
494 // Go over all connections and check if any of them are SV
496 if_expander
.visit_connections(*cell
, *mod
);
498 if (flag_check
|| flag_simcheck
)
499 check_cell_connections(*module
, *cell
, *mod
);
501 if (mod
->get_blackbox_attribute()) {
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());
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
514 if_expander
.rewrite_interface_connections(*cell
);
516 // If there are no overridden parameters AND not interfaces, then we can use the existing module instance as the type
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
;
529 cell
->type
= mod
->derive(design
,
531 if_expander
.interfaces_to_add_to_submodule
,
532 if_expander
.modports_used_in_submodule
);
533 cell
->parameters
.clear();
534 did_something
= true;
536 handle_interface_instance
:
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;
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
);
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
);
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
;
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
))
566 for (auto &it
: array_cells
)
568 RTLIL::Cell
*cell
= it
.first
;
569 int idx
= it
.second
.first
, num
= it
.second
.second
;
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
));
574 RTLIL::Module
*mod
= design
->module(cell
->type
);
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
;
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)
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
);
598 return did_something
;
601 void hierarchy_worker(RTLIL::Design
*design
, std::set
<RTLIL::Module
*, IdString::compare_ptr_by_name
<Module
>> &used
, RTLIL::Module
*mod
, int indent
)
603 if (used
.count(mod
) > 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());
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);
621 void hierarchy_clean(RTLIL::Design
*design
, RTLIL::Module
*top
, bool purge_lib
)
623 std::set
<RTLIL::Module
*, IdString::compare_ptr_by_name
<Module
>> used
;
624 hierarchy_worker(design
, used
, top
, 0);
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
);
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
);
639 if (del_wires
.size() > 0) {
640 mod
->remove(del_wires
);
646 for (auto mod
: del_modules
) {
647 if (!purge_lib
&& mod
->get_blackbox_attribute())
649 log("Removing unused module `%s'.\n", mod
->name
.c_str());
654 log("Removed %d unused modules.\n", del_counter
);
657 bool set_keep_assert(std::map
<RTLIL::Module
*, bool> &cache
, RTLIL::Module
*mod
)
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;
668 int find_top_mod_score(Design
*design
, Module
*module
, dict
<Module
*, int> &db
)
670 if (db
.count(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);
687 return db
.at(module
);
690 RTLIL::Module
*check_if_top_has_changed(Design
*design
, Module
*top_mod
)
692 if(top_mod
!= NULL
&& top_mod
->get_bool_attribute(ID::initial_top
))
695 for (auto mod
: design
->modules()) {
696 if (mod
->get_bool_attribute(ID::top
)) {
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
)
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)
714 return module
->wire(port
);
717 struct HierarchyPass
: public Pass
{
718 HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
721 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
723 log(" hierarchy [-check] [-top <module>]\n");
724 log(" hierarchy -generate <cell-types> <port-decls>\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");
733 log(" also check the design hierarchy. this generates an error when\n");
734 log(" an unknown module is used as cell type.\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");
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");
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");
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");
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");
758 log(" -nodefaults\n");
759 log(" do not resolve input port default values\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");
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");
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");
775 log(" automatically determine the top of the design hierarchy and mark it.\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");
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");
788 log(" {i|o|io}[@<num>]:<portname>\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");
796 log("This pass ignores the current selection and always operates on all modules\n");
797 log("in the current design.\n");
800 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
802 log_header(design
, "Executing HIERARCHY pass (managing design hierarchy).\n");
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
;
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
;
822 for (argidx
= 1; argidx
< args
.size(); argidx
++)
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;
833 decl
.input
= true, decl
.output
= false, p
++;
835 decl
.input
= false, decl
.output
= true, p
++;
840 decl
.index
= strtol(++p
, &endptr
, 10);
851 log("Port declaration: %s", decl
.input
? decl
.output
? "inout" : "input" : "output");
853 log(" [at position %d]", decl
.index
);
854 log(" %s\n", decl
.portname
.c_str());
855 generate_ports
.push_back(decl
);
858 log("Celltype: %s\n", args
[argidx
].c_str());
859 generate_cells
.push_back(RTLIL::unescape_id(args
[argidx
]));
863 if (args
[argidx
] == "-check") {
867 if (args
[argidx
] == "-simcheck") {
868 flag_simcheck
= true;
871 if (args
[argidx
] == "-purge_lib") {
875 if (args
[argidx
] == "-keep_positionals") {
876 keep_positionals
= true;
879 if (args
[argidx
] == "-keep_portwidths") {
880 keep_portwidths
= true;
883 if (args
[argidx
] == "-nodefaults") {
887 if (args
[argidx
] == "-nokeep_asserts") {
888 nokeep_asserts
= true;
891 if (args
[argidx
] == "-libdir" && argidx
+1 < args
.size()) {
892 libdirs
.push_back(args
[++argidx
]);
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
];
901 if (args
[argidx
] == "-auto-top") {
902 auto_top_mode
= true;
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
);
910 log_warning("-chparam %s already specified: overwriting.\n", key
.c_str());
911 r
.first
->second
= value
;
917 extra_args(args
, argidx
, design
, false);
919 if (!load_top_mod
.empty())
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
);
925 dict
<RTLIL::IdString
, RTLIL::Const
> top_parameters
;
926 if ((top_mod
== nullptr && design
->module(abstract_id
)) || top_mod
!= nullptr) {
927 for (auto ¶
: parameters
) {
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();
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
));
940 if (top_mod
!= nullptr && top_mod
->name
!= top_name
) {
941 Module
*m
= top_mod
->clone();
943 Module
*old_mod
= design
->module(top_name
);
945 design
->remove(old_mod
);
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
));
959 log_cmd_error("Module `%s' not found!\n", load_top_mod
.c_str());
961 #ifdef YOSYS_ENABLE_VERIFIC
962 if (verific_import_pending
)
963 verific_import(design
, parameters
);
968 generate(design
, generate_cells
, generate_ports
);
974 if (top_mod
== nullptr)
975 for (auto mod
: design
->modules())
976 if (mod
->get_bool_attribute(ID::top
))
979 if (top_mod
!= nullptr && top_mod
->name
.begins_with("$abstract")) {
980 IdString top_name
= top_mod
->name
.substr(strlen("$abstract"));
982 dict
<RTLIL::IdString
, RTLIL::Const
> top_parameters
;
983 for (auto ¶
: parameters
) {
985 if (!RTLIL::SigSpec::parse(sig_value
, NULL
, para
.second
))
986 log_cmd_error("Can't decode value '%s'!\n", para
.second
.c_str());
987 top_parameters
[RTLIL::escape_id(para
.first
)] = sig_value
.as_const();
990 top_mod
= design
->module(top_mod
->derive(design
, top_parameters
));
992 if (top_mod
!= nullptr && top_mod
->name
!= top_name
) {
993 Module
*m
= top_mod
->clone();
995 Module
*old_mod
= design
->module(top_name
);
997 design
->remove(old_mod
);
1003 if (top_mod
== nullptr && auto_top_mode
) {
1004 log_header(design
, "Finding top of design hierarchy..\n");
1005 dict
<Module
*, int> db
;
1006 for (Module
*mod
: design
->selected_modules()) {
1007 int score
= find_top_mod_score(design
, mod
, db
);
1008 log("root of %3d design levels: %-20s\n", score
, log_id(mod
));
1009 if (!top_mod
|| score
> db
[top_mod
])
1012 if (top_mod
!= nullptr)
1013 log("Automatically selected %s as design top module.\n", log_id(top_mod
));
1016 if (flag_simcheck
&& top_mod
== nullptr)
1017 log_error("Design has no top module.\n");
1019 if (top_mod
!= NULL
) {
1020 for (auto mod
: design
->modules())
1022 mod
->attributes
[ID::initial_top
] = RTLIL::Const(1);
1024 mod
->attributes
.erase(ID::initial_top
);
1027 bool did_something
= true;
1028 while (did_something
)
1030 did_something
= false;
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);
1037 for (auto mod
: design
->modules())
1038 used_modules
.insert(mod
);
1041 for (auto module
: used_modules
) {
1042 if (expand_module(design
, module
, flag_check
, flag_simcheck
, libdirs
))
1043 did_something
= true;
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;
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
);
1063 for(size_t i
=0; i
<modules_to_delete
.size(); i
++) {
1064 design
->remove(modules_to_delete
[i
]);
1069 if (top_mod
!= NULL
) {
1070 log_header(design
, "Analyzing design hierarchy..\n");
1071 hierarchy_clean(design
, top_mod
, purge_lib
);
1074 if (top_mod
!= NULL
) {
1075 for (auto mod
: design
->modules()) {
1077 mod
->attributes
[ID::top
] = RTLIL::Const(1);
1079 mod
->attributes
.erase(ID::top
);
1080 mod
->attributes
.erase(ID::initial_top
);
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
);
1093 if (!keep_positionals
)
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
;
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)
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
));
1111 pool
<std::pair
<IdString
, IdString
>> params_rename
;
1112 for (const auto &p
: cell
->parameters
) {
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
));
1119 params_rename
.insert(std::make_pair(p
.first
, cell_mod
->avail_parameters
[id
- 1]));
1123 for (const auto &p
: params_rename
) {
1124 cell
->setParam(p
.second
, cell
->getParam(p
.first
));
1125 cell
->unsetParam(p
.first
);
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
;
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()) {
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
;
1150 new_connections
[pos_map
.at(key
)] = conn
.second
;
1152 new_connections
[conn
.first
] = conn
.second
;
1154 cell
->connections_
= new_connections
;
1158 // Determine default values
1159 dict
<IdString
, dict
<IdString
, Const
>> defaults_db
;
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
);
1167 // Process SV implicit wildcard port connections
1168 std::set
<Module
*> blackbox_derivatives
;
1169 std::vector
<Module
*> design_modules
= design
->modules();
1171 for (auto module
: design_modules
)
1173 for (auto cell
: module
->cells())
1175 if (!cell
->get_bool_attribute(ID::wildcard_port_conns
))
1177 Module
*m
= design
->module(cell
->type
);
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
));
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())
1188 if (new_m_name
!= m
->name
) {
1189 m
= design
->module(new_m_name
);
1190 blackbox_derivatives
.insert(m
);
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
)
1199 if (old_connections
.count(wire
->name
))
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());
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
))
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
);
1217 cell
->attributes
.erase(ID::wildcard_port_conns
);
1223 for (auto module
: design
->modules())
1224 for (auto cell
: module
->cells())
1226 if (defaults_db
.count(cell
->type
) == 0)
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
)
1238 for (auto &it
: defaults_db
.at(cell
->type
))
1239 if (!cell
->hasPort(it
.first
))
1240 cell
->setPort(it
.first
, it
.second
);
1244 for (auto module
: design_modules
)
1246 pool
<Wire
*> wand_wor_index
;
1247 dict
<Wire
*, SigSpec
> wand_map
, wor_map
;
1248 vector
<SigSig
> new_connections
;
1250 for (auto wire
: module
->wires())
1252 if (wire
->get_bool_attribute(ID::wand
)) {
1253 wand_map
[wire
] = SigSpec();
1254 wand_wor_index
.insert(wire
);
1256 if (wire
->get_bool_attribute(ID::wor
)) {
1257 wor_map
[wire
] = SigSpec();
1258 wand_wor_index
.insert(wire
);
1262 for (auto &conn
: module
->connections())
1267 for (auto c
: conn
.first
.chunks())
1270 SigSpec rhs
= conn
.second
.extract(cursor
, GetSize(c
));
1272 if (wand_wor_index
.count(w
) == 0) {
1273 new_conn
.first
.append(c
);
1274 new_conn
.second
.append(rhs
);
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
);
1281 SigSpec sig
= SigSpec(State::S0
, GetSize(w
));
1282 sig
.replace(c
.offset
, rhs
);
1283 wor_map
.at(w
).append(sig
);
1286 cursor
+= GetSize(c
);
1288 new_connections
.push_back(new_conn
);
1290 module
->new_connections(new_connections
);
1292 for (auto cell
: module
->cells())
1297 for (auto &conn
: cell
->connections())
1299 if (!cell
->output(conn
.first
))
1303 bool update_port
= false;
1305 for (auto c
: conn
.second
.chunks())
1309 if (wand_wor_index
.count(w
) == 0) {
1314 Wire
*t
= module
->addWire(NEW_ID
, GetSize(c
));
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
);
1323 SigSpec sig
= SigSpec(State::S0
, GetSize(w
));
1324 sig
.replace(c
.offset
, t
);
1325 wor_map
.at(w
).append(sig
);
1330 cell
->setPort(conn
.first
, new_sig
);
1334 for (auto w
: wand_wor_index
)
1336 bool wand
= wand_map
.count(w
);
1337 SigSpec sigs
= wand
? wand_map
.at(w
) : wor_map
.at(w
);
1339 if (GetSize(sigs
) == 0)
1342 if (GetSize(w
) == 1) {
1344 module
->addReduceAnd(NEW_ID
, sigs
, w
);
1346 module
->addReduceOr(NEW_ID
, sigs
, w
);
1350 SigSpec s
= sigs
.extract(0, GetSize(w
));
1351 for (int i
= GetSize(w
); i
< GetSize(sigs
); i
+= GetSize(w
)) {
1353 s
= module
->And(NEW_ID
, s
, sigs
.extract(i
, GetSize(w
)));
1355 s
= module
->Or(NEW_ID
, s
, sigs
.extract(i
, GetSize(w
)));
1357 module
->connect(w
, s
);
1360 for (auto cell
: module
->cells())
1362 Module
*m
= design
->module(cell
->type
);
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())
1371 if (new_m_name
!= m
->name
) {
1372 m
= design
->module(new_m_name
);
1373 blackbox_derivatives
.insert(m
);
1377 for (auto &conn
: cell
->connections())
1379 Wire
*w
= m
->wire(conn
.first
);
1381 if (w
== nullptr || w
->port_id
== 0)
1384 if (GetSize(conn
.second
) == 0)
1387 SigSpec sig
= conn
.second
;
1389 if (!keep_portwidths
&& GetSize(w
) != GetSize(conn
.second
))
1391 if (GetSize(w
) < GetSize(conn
.second
))
1393 int n
= GetSize(conn
.second
) - GetSize(w
);
1394 if (!w
->port_input
&& w
->port_output
)
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
));
1400 sig
.remove(GetSize(w
), n
);
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
);
1408 sig
.append(module
->addWire(NEW_ID
, n
));
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
);
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
));
1424 for (auto module
: blackbox_derivatives
)
1425 design
->remove(module
);
1431 PRIVATE_NAMESPACE_END