2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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 i1
: design
->modules_
)
46 for (auto i2
: i1
.second
->cells_
)
48 RTLIL::Cell
*cell
= i2
.second
;
49 if (design
->has(cell
->type
))
51 if (cell
->type
.begins_with("$__"))
53 for (auto &pattern
: celltypes
)
54 if (patmatch(pattern
.c_str(), RTLIL::unescape_id(cell
->type
).c_str()))
55 found_celltypes
.insert(cell
->type
);
58 for (auto &celltype
: found_celltypes
)
60 std::set
<RTLIL::IdString
> portnames
;
61 std::set
<RTLIL::IdString
> parameters
;
62 std::map
<RTLIL::IdString
, int> portwidths
;
63 log("Generate module for cell type %s:\n", celltype
.c_str());
65 for (auto i1
: design
->modules_
)
66 for (auto i2
: i1
.second
->cells_
)
67 if (i2
.second
->type
== celltype
) {
68 for (auto &conn
: i2
.second
->connections()) {
69 if (conn
.first
[0] != '$')
70 portnames
.insert(conn
.first
);
71 portwidths
[conn
.first
] = max(portwidths
[conn
.first
], conn
.second
.size());
73 for (auto ¶
: i2
.second
->parameters
)
74 parameters
.insert(para
.first
);
77 for (auto &decl
: portdecls
)
79 portnames
.insert(decl
.portname
);
81 std::set
<int> indices
;
82 for (int i
= 0; i
< int(portnames
.size()); i
++)
85 std::vector
<generate_port_decl_t
> ports(portnames
.size());
87 for (auto &decl
: portdecls
)
89 portwidths
[decl
.portname
] = max(portwidths
[decl
.portname
], 1);
90 portwidths
[decl
.portname
] = max(portwidths
[decl
.portname
], portwidths
[stringf("$%d", decl
.index
)]);
91 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
));
92 if (indices
.count(decl
.index
) > ports
.size())
93 log_error("Port index (%d) exceeds number of found ports (%d).\n", decl
.index
, int(ports
.size()));
94 if (indices
.count(decl
.index
) == 0)
95 log_error("Conflict on port index %d.\n", decl
.index
);
96 indices
.erase(decl
.index
);
97 portnames
.erase(decl
.portname
);
98 ports
[decl
.index
-1] = decl
;
101 while (portnames
.size() > 0) {
102 RTLIL::IdString portname
= *portnames
.begin();
103 for (auto &decl
: portdecls
)
104 if (decl
.index
== 0 && patmatch(decl
.portname
.c_str(), RTLIL::unescape_id(portname
).c_str())) {
105 generate_port_decl_t d
= decl
;
106 d
.portname
= portname
.str();
107 d
.index
= *indices
.begin();
108 log_assert(!indices
.empty());
109 indices
.erase(d
.index
);
110 ports
[d
.index
-1] = d
;
111 portwidths
[d
.portname
] = max(portwidths
[d
.portname
], 1);
112 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
));
113 goto found_matching_decl
;
115 log_error("Can't match port %s.\n", RTLIL::id2cstr(portname
));
116 found_matching_decl
:;
117 portnames
.erase(portname
);
120 log_assert(indices
.empty());
122 RTLIL::Module
*mod
= new RTLIL::Module
;
123 mod
->name
= celltype
;
124 mod
->attributes
["\\blackbox"] = RTLIL::Const(1);
127 for (auto &decl
: ports
) {
128 RTLIL::Wire
*wire
= mod
->addWire(decl
.portname
, portwidths
.at(decl
.portname
));
129 wire
->port_id
= decl
.index
;
130 wire
->port_input
= decl
.input
;
131 wire
->port_output
= decl
.output
;
136 for (auto ¶
: parameters
)
137 log(" ignoring parameter %s.\n", RTLIL::id2cstr(para
));
139 log(" module %s created.\n", RTLIL::id2cstr(mod
->name
));
143 // Return the "basic" type for an array item.
144 std::string
basic_cell_type(const std::string celltype
, int pos
[3] = nullptr) {
145 std::string basicType
= celltype
;
146 if (celltype
.compare(0, strlen("$array:"), "$array:") == 0) {
147 int pos_idx
= celltype
.find_first_of(':');
148 int pos_num
= celltype
.find_first_of(':', pos_idx
+ 1);
149 int pos_type
= celltype
.find_first_of(':', pos_num
+ 1);
150 basicType
= celltype
.substr(pos_type
+ 1);
151 if (pos
!= nullptr) {
160 bool expand_module(RTLIL::Design
*design
, RTLIL::Module
*module
, bool flag_check
, bool flag_simcheck
, std::vector
<std::string
> &libdirs
)
162 bool did_something
= false;
163 std::map
<RTLIL::Cell
*, std::pair
<int, int>> array_cells
;
164 std::string filename
;
166 bool has_interface_ports
= false;
168 // If any of the ports are actually interface ports, we will always need to
169 // reprocess the module:
170 if(!module
->get_bool_attribute("\\interfaces_replaced_in_module")) {
171 for (auto &wire
: module
->wires_
) {
172 if ((wire
.second
->port_input
|| wire
.second
->port_output
) && wire
.second
->get_bool_attribute("\\is_interface"))
173 has_interface_ports
= true;
177 // Always keep track of all derived interfaces available in the current module in 'interfaces_in_module':
178 dict
<RTLIL::IdString
, RTLIL::Module
*> interfaces_in_module
;
179 for (auto &cell_it
: module
->cells_
)
181 RTLIL::Cell
*cell
= cell_it
.second
;
182 if(cell
->get_bool_attribute("\\is_interface")) {
183 RTLIL::Module
*intf_module
= design
->modules_
[cell
->type
];
184 interfaces_in_module
[cell
->name
] = intf_module
;
188 for (auto &cell_it
: module
->cells_
)
190 RTLIL::Cell
*cell
= cell_it
.second
;
191 bool has_interfaces_not_found
= false;
193 std::vector
<RTLIL::IdString
> connections_to_remove
;
194 std::vector
<RTLIL::IdString
> connections_to_add_name
;
195 std::vector
<RTLIL::SigSpec
> connections_to_add_signal
;
197 if (cell
->type
.begins_with("$array:")) {
199 basic_cell_type(cell
->type
.str(), pos
);
200 int pos_idx
= pos
[0];
201 int pos_num
= pos
[1];
202 int pos_type
= pos
[2];
203 int idx
= atoi(cell
->type
.substr(pos_idx
+ 1, pos_num
).c_str());
204 int num
= atoi(cell
->type
.substr(pos_num
+ 1, pos_type
).c_str());
205 array_cells
[cell
] = std::pair
<int, int>(idx
, num
);
206 cell
->type
= cell
->type
.substr(pos_type
+ 1);
208 dict
<RTLIL::IdString
, RTLIL::Module
*> interfaces_to_add_to_submodule
;
209 dict
<RTLIL::IdString
, RTLIL::IdString
> modports_used_in_submodule
;
211 if (design
->modules_
.count(cell
->type
) == 0)
213 if (design
->modules_
.count("$abstract" + cell
->type
.str()))
215 cell
->type
= design
->modules_
.at("$abstract" + cell
->type
.str())->derive(design
, cell
->parameters
);
216 cell
->parameters
.clear();
217 did_something
= true;
221 if (cell
->type
[0] == '$')
224 for (auto &dir
: libdirs
)
226 static const vector
<pair
<string
, string
>> extensions_list
=
229 {".sv", "verilog -sv"},
233 for (auto &ext
: extensions_list
)
235 filename
= dir
+ "/" + RTLIL::unescape_id(cell
->type
) + ext
.first
;
236 if (check_file_exists(filename
)) {
237 Frontend::frontend_call(design
, NULL
, filename
, ext
.second
);
243 if ((flag_check
|| flag_simcheck
) && cell
->type
[0] != '$')
244 log_error("Module `%s' referenced in module `%s' in cell `%s' is not part of the design.\n",
245 cell
->type
.c_str(), module
->name
.c_str(), cell
->name
.c_str());
249 if (design
->modules_
.count(cell
->type
) == 0)
250 log_error("File `%s' from libdir does not declare module `%s'.\n", filename
.c_str(), cell
->type
.c_str());
251 did_something
= true;
254 RTLIL::Module
*mod
= design
->module(cell
->type
);
256 // Go over all connections and see if any of them are SV interfaces. If they are, then add the replacements to
257 // some lists, so that the ports for sub-modules can be replaced further down:
258 for (auto &conn
: cell
->connections()) {
259 if(mod
->wires_
.count(conn
.first
) != 0 && mod
->wire(conn
.first
)->get_bool_attribute("\\is_interface")) { // Check if the connection is present as an interface in the sub-module's port list
260 //const pool<string> &interface_type_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_type");
261 //for (auto &d : interface_type_pool) { // TODO: Compare interface type to type in parent module (not crucially important, but good for robustness)
264 // Find if the sub-module has set a modport for the current interface connection:
265 const pool
<string
> &interface_modport_pool
= mod
->wire(conn
.first
)->get_strpool_attribute("\\interface_modport");
266 std::string interface_modport
= "";
267 for (auto &d
: interface_modport_pool
) {
268 interface_modport
= "\\" + d
;
270 if(conn
.second
.bits().size() == 1 && conn
.second
.bits()[0].wire
->get_bool_attribute("\\is_interface")) { // Check if the connected wire is a potential interface in the parent module
271 std::string interface_name_str
= conn
.second
.bits()[0].wire
->name
.str();
272 interface_name_str
.replace(0,23,""); // Strip the prefix '$dummywireforinterface' from the dummy wire to get the name
273 interface_name_str
= "\\" + interface_name_str
;
274 RTLIL::IdString interface_name
= interface_name_str
;
275 bool not_found_interface
= false;
276 if(module
->get_bool_attribute("\\interfaces_replaced_in_module")) { // If 'interfaces' in the cell have not be been handled yet, there is no need to derive the sub-module either
277 // Check if the interface instance is present in module:
278 // Interface instances may either have the plain name or the name appended with '_inst_from_top_dummy'.
279 // Check for both of them here
280 int nexactmatch
= interfaces_in_module
.count(interface_name
) > 0;
281 std::string interface_name_str2
= interface_name_str
+ "_inst_from_top_dummy";
282 RTLIL::IdString interface_name2
= interface_name_str2
;
283 int nmatch2
= interfaces_in_module
.count(interface_name2
) > 0;
284 if (nexactmatch
> 0 || nmatch2
> 0) {
285 if (nexactmatch
!= 0) // Choose the one with the plain name if it exists
286 interface_name2
= interface_name
;
287 RTLIL::Module
*mod_replace_ports
= interfaces_in_module
.at(interface_name2
);
288 for (auto &mod_wire
: mod_replace_ports
->wires_
) { // Go over all wires in interface, and add replacements to lists.
289 std::string signal_name1
= conn
.first
.str() + "." + log_id(mod_wire
.first
);
290 std::string signal_name2
= interface_name
.str() + "." + log_id(mod_wire
.first
);
291 connections_to_add_name
.push_back(RTLIL::IdString(signal_name1
));
292 if(module
->wires_
.count(signal_name2
) == 0) {
293 log_error("Could not find signal '%s' in '%s'\n", signal_name2
.c_str(), log_id(module
->name
));
296 RTLIL::Wire
*wire_in_parent
= module
->wire(signal_name2
);
297 connections_to_add_signal
.push_back(wire_in_parent
);
300 connections_to_remove
.push_back(conn
.first
);
301 interfaces_to_add_to_submodule
[conn
.first
] = interfaces_in_module
.at(interface_name2
);
303 // Add modports to a dict which will be passed to AstModule::derive
304 if (interface_modport
!= "") {
305 modports_used_in_submodule
[conn
.first
] = interface_modport
;
308 else not_found_interface
= true;
310 else not_found_interface
= true;
311 // If the interface instance has not already been derived in the module, we cannot complete at this stage. Set "has_interfaces_not_found"
312 // which will delay the expansion of this cell:
313 if (not_found_interface
) {
314 // If we have already gone over all cells in this module, and the interface has still not been found - flag it as an error:
315 if(!(module
->get_bool_attribute("\\cells_not_processed"))) {
316 log_warning("Could not find interface instance for `%s' in `%s'\n", log_id(interface_name
), log_id(module
));
319 // Only set has_interfaces_not_found if it would be possible to find them, since otherwiser we will end up in an infinite loop:
320 has_interfaces_not_found
= true;
328 if (flag_check
|| flag_simcheck
)
330 for (auto &conn
: cell
->connections()) {
331 if (conn
.first
[0] == '$' && '0' <= conn
.first
[1] && conn
.first
[1] <= '9') {
332 int id
= atoi(conn
.first
.c_str()+1);
333 if (id
<= 0 || id
> GetSize(mod
->ports
))
334 log_error("Module `%s' referenced in module `%s' in cell `%s' has only %d ports, requested port %d.\n",
335 log_id(cell
->type
), log_id(module
), log_id(cell
), GetSize(mod
->ports
), id
);
336 } else if (mod
->wire(conn
.first
) == nullptr || mod
->wire(conn
.first
)->port_id
== 0)
337 log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n",
338 log_id(cell
->type
), log_id(module
), log_id(cell
), log_id(conn
.first
));
340 for (auto ¶m
: cell
->parameters
)
341 if (mod
->avail_parameters
.count(param
.first
) == 0 && param
.first
[0] != '$' && strchr(param
.first
.c_str(), '.') == NULL
)
342 log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n",
343 log_id(cell
->type
), log_id(module
), log_id(cell
), log_id(param
.first
));
347 RTLIL::Module
*mod
= design
->modules_
[cell
->type
];
349 if (design
->modules_
.at(cell
->type
)->get_blackbox_attribute()) {
351 log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n",
352 cell
->type
.c_str(), module
->name
.c_str(), cell
->name
.c_str());
356 // If interface instances not yet found, skip cell for now, and say we did something, so that we will return back here:
357 if(has_interfaces_not_found
) {
358 did_something
= true; // waiting for interfaces to be handled
362 // Do the actual replacements of the SV interface port connection with the individual signal connections:
363 for(unsigned int i
=0;i
<connections_to_add_name
.size();i
++) {
364 cell
->connections_
[connections_to_add_name
[i
]] = connections_to_add_signal
[i
];
366 // Remove the connection for the interface itself:
367 for(unsigned int i
=0;i
<connections_to_remove
.size();i
++) {
368 cell
->connections_
.erase(connections_to_remove
[i
]);
371 // If there are no overridden parameters AND not interfaces, then we can use the existing module instance as the type
373 if (cell
->parameters
.size() == 0 && (interfaces_to_add_to_submodule
.size() == 0 || !(cell
->get_bool_attribute("\\module_not_derived")))) {
374 // If the cell being processed is an the interface instance itself, go down to "handle_interface_instance:",
375 // so that the signals of the interface are added to the parent module.
376 if (mod
->get_bool_attribute("\\is_interface")) {
377 goto handle_interface_instance
;
382 cell
->type
= mod
->derive(design
, cell
->parameters
, interfaces_to_add_to_submodule
, modports_used_in_submodule
);
383 cell
->parameters
.clear();
384 did_something
= true;
386 handle_interface_instance
:
388 // We add all the signals of the interface explicitly to the parent module. This is always needed when we encounter
389 // an interface instance:
390 if (mod
->get_bool_attribute("\\is_interface") && cell
->get_bool_attribute("\\module_not_derived")) {
391 cell
->set_bool_attribute("\\is_interface");
392 RTLIL::Module
*derived_module
= design
->modules_
[cell
->type
];
393 interfaces_in_module
[cell
->name
] = derived_module
;
394 did_something
= true;
396 // We clear 'module_not_derived' such that we will not rederive the cell again (needed when there are interfaces connected to the cell)
397 cell
->attributes
.erase("\\module_not_derived");
399 // Clear the attribute 'cells_not_processed' such that it can be known that we
400 // have been through all cells at least once, and that we can know whether
401 // to flag an error because of interface instances not found:
402 module
->attributes
.erase("\\cells_not_processed");
405 // If any interface instances or interface ports were found in the module, we need to rederive it completely:
406 if ((interfaces_in_module
.size() > 0 || has_interface_ports
) && !module
->get_bool_attribute("\\interfaces_replaced_in_module")) {
407 module
->reprocess_module(design
, interfaces_in_module
);
408 return did_something
;
412 for (auto &it
: array_cells
)
414 RTLIL::Cell
*cell
= it
.first
;
415 int idx
= it
.second
.first
, num
= it
.second
.second
;
417 if (design
->modules_
.count(cell
->type
) == 0)
418 log_error("Array cell `%s.%s' of unknown type `%s'.\n", RTLIL::id2cstr(module
->name
), RTLIL::id2cstr(cell
->name
), RTLIL::id2cstr(cell
->type
));
420 RTLIL::Module
*mod
= design
->modules_
[cell
->type
];
422 for (auto &conn
: cell
->connections_
) {
423 int conn_size
= conn
.second
.size();
424 RTLIL::IdString portname
= conn
.first
;
425 if (portname
.begins_with("$")) {
426 int port_id
= atoi(portname
.substr(1).c_str());
427 for (auto &wire_it
: mod
->wires_
)
428 if (wire_it
.second
->port_id
== port_id
) {
429 portname
= wire_it
.first
;
433 if (mod
->wires_
.count(portname
) == 0)
434 log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module
->name
), RTLIL::id2cstr(cell
->name
), RTLIL::id2cstr(conn
.first
));
435 int port_size
= mod
->wires_
.at(portname
)->width
;
436 if (conn_size
== port_size
|| conn_size
== 0)
438 if (conn_size
!= port_size
*num
)
439 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
));
440 conn
.second
= conn
.second
.extract(port_size
*idx
, port_size
);
444 return did_something
;
447 void hierarchy_worker(RTLIL::Design
*design
, std::set
<RTLIL::Module
*, IdString::compare_ptr_by_name
<Module
>> &used
, RTLIL::Module
*mod
, int indent
)
449 if (used
.count(mod
) > 0)
453 log("Top module: %s\n", mod
->name
.c_str());
454 else if (!mod
->get_blackbox_attribute())
455 log("Used module: %*s%s\n", indent
, "", mod
->name
.c_str());
458 for (auto cell
: mod
->cells()) {
459 std::string celltype
= cell
->type
.str();
460 if (celltype
.compare(0, strlen("$array:"), "$array:") == 0)
461 celltype
= basic_cell_type(celltype
);
462 if (design
->module(celltype
))
463 hierarchy_worker(design
, used
, design
->module(celltype
), indent
+4);
467 void hierarchy_clean(RTLIL::Design
*design
, RTLIL::Module
*top
, bool purge_lib
)
469 std::set
<RTLIL::Module
*, IdString::compare_ptr_by_name
<Module
>> used
;
470 hierarchy_worker(design
, used
, top
, 0);
472 std::vector
<RTLIL::Module
*> del_modules
;
473 for (auto &it
: design
->modules_
)
474 if (used
.count(it
.second
) == 0)
475 del_modules
.push_back(it
.second
);
477 // Now all interface ports must have been exploded, and it is hence
478 // safe to delete all of the remaining dummy interface ports:
479 pool
<RTLIL::Wire
*> del_wires
;
480 for(auto &wire
: it
.second
->wires_
) {
481 if ((wire
.second
->port_input
|| wire
.second
->port_output
) && wire
.second
->get_bool_attribute("\\is_interface")) {
482 del_wires
.insert(wire
.second
);
485 if (del_wires
.size() > 0) {
486 it
.second
->remove(del_wires
);
487 it
.second
->fixup_ports();
492 for (auto mod
: del_modules
) {
493 if (!purge_lib
&& mod
->get_blackbox_attribute())
495 log("Removing unused module `%s'.\n", mod
->name
.c_str());
496 design
->modules_
.erase(mod
->name
);
501 log("Removed %d unused modules.\n", del_counter
);
504 bool set_keep_assert(std::map
<RTLIL::Module
*, bool> &cache
, RTLIL::Module
*mod
)
506 if (cache
.count(mod
) == 0)
507 for (auto c
: mod
->cells()) {
508 RTLIL::Module
*m
= mod
->design
->module(c
->type
);
509 if ((m
!= nullptr && set_keep_assert(cache
, m
)) || c
->type
.in("$assert", "$assume", "$live", "$fair", "$cover"))
510 return cache
[mod
] = true;
515 int find_top_mod_score(Design
*design
, Module
*module
, dict
<Module
*, int> &db
)
517 if (db
.count(module
) == 0) {
520 for (auto cell
: module
->cells()) {
521 std::string celltype
= cell
->type
.str();
522 // Is this an array instance
523 if (celltype
.compare(0, strlen("$array:"), "$array:") == 0)
524 celltype
= basic_cell_type(celltype
);
525 // Is this cell a module instance?
526 auto instModule
= design
->module(celltype
);
527 // If there is no instance for this, issue a warning.
528 if (instModule
!= nullptr) {
529 score
= max(score
, find_top_mod_score(design
, instModule
, db
) + 1);
534 return db
.at(module
);
537 RTLIL::Module
*check_if_top_has_changed(Design
*design
, Module
*top_mod
)
539 if(top_mod
!= NULL
&& top_mod
->get_bool_attribute("\\initial_top"))
542 for (auto mod
: design
->modules()) {
543 if (mod
->get_bool_attribute("\\top")) {
551 struct HierarchyPass
: public Pass
{
552 HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
553 void help() YS_OVERRIDE
555 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
557 log(" hierarchy [-check] [-top <module>]\n");
558 log(" hierarchy -generate <cell-types> <port-decls>\n");
560 log("In parametric designs, a module might exists in several variations with\n");
561 log("different parameter values. This pass looks at all modules in the current\n");
562 log("design an re-runs the language frontends for the parametric modules as\n");
563 log("needed. It also resolves assignments to wired logic data types (wand/wor),\n");
564 log("resolves positional module parameters, unroll array instances, and more.\n");
567 log(" also check the design hierarchy. this generates an error when\n");
568 log(" an unknown module is used as cell type.\n");
571 log(" like -check, but also throw an error if blackbox modules are\n");
572 log(" instantiated, and throw an error if the design has no top module.\n");
574 log(" -purge_lib\n");
575 log(" by default the hierarchy command will not remove library (blackbox)\n");
576 log(" modules. use this option to also remove unused blackbox modules.\n");
578 log(" -libdir <directory>\n");
579 log(" search for files named <module_name>.v in the specified directory\n");
580 log(" for unknown modules and automatically run read_verilog for each\n");
581 log(" unknown module.\n");
583 log(" -keep_positionals\n");
584 log(" per default this pass also converts positional arguments in cells\n");
585 log(" to arguments using port names. This option disables this behavior.\n");
587 log(" -keep_portwidths\n");
588 log(" per default this pass adjusts the port width on cells that are\n");
589 log(" module instances when the width does not match the module port. This\n");
590 log(" option disables this behavior.\n");
592 log(" -nodefaults\n");
593 log(" do not resolve input port default values\n");
595 log(" -nokeep_asserts\n");
596 log(" per default this pass sets the \"keep\" attribute on all modules\n");
597 log(" that directly or indirectly contain one or more formal properties.\n");
598 log(" This option disables this behavior.\n");
600 log(" -top <module>\n");
601 log(" use the specified top module to build the design hierarchy. Modules\n");
602 log(" outside this tree (unused modules) are removed.\n");
604 log(" when the -top option is used, the 'top' attribute will be set on the\n");
605 log(" specified top module. otherwise a module with the 'top' attribute set\n");
606 log(" will implicitly be used as top module, if such a module exists.\n");
609 log(" automatically determine the top of the design hierarchy and mark it.\n");
611 log(" -chparam name value \n");
612 log(" elaborate the top module using this parameter value. Modules on which\n");
613 log(" this parameter does not exist may cause a warning message to be output.\n");
614 log(" This option can be specified multiple times to override multiple\n");
615 log(" parameters. String values must be passed in double quotes (\").\n");
617 log("In -generate mode this pass generates blackbox modules for the given cell\n");
618 log("types (wildcards supported). For this the design is searched for cells that\n");
619 log("match the given types and then the given port declarations are used to\n");
620 log("determine the direction of the ports. The syntax for a port declaration is:\n");
622 log(" {i|o|io}[@<num>]:<portname>\n");
624 log("Input ports are specified with the 'i' prefix, output ports with the 'o'\n");
625 log("prefix and inout ports with the 'io' prefix. The optional <num> specifies\n");
626 log("the position of the port in the parameter list (needed when instantiated\n");
627 log("using positional arguments). When <num> is not specified, the <portname> can\n");
628 log("also contain wildcard characters.\n");
630 log("This pass ignores the current selection and always operates on all modules\n");
631 log("in the current design.\n");
634 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
636 log_header(design
, "Executing HIERARCHY pass (managing design hierarchy).\n");
638 bool flag_check
= false;
639 bool flag_simcheck
= false;
640 bool purge_lib
= false;
641 RTLIL::Module
*top_mod
= NULL
;
642 std::string load_top_mod
;
643 std::vector
<std::string
> libdirs
;
645 bool auto_top_mode
= false;
646 bool generate_mode
= false;
647 bool keep_positionals
= false;
648 bool keep_portwidths
= false;
649 bool nodefaults
= false;
650 bool nokeep_asserts
= false;
651 std::vector
<std::string
> generate_cells
;
652 std::vector
<generate_port_decl_t
> generate_ports
;
653 std::map
<std::string
, std::string
> parameters
;
656 for (argidx
= 1; argidx
< args
.size(); argidx
++)
658 if (args
[argidx
] == "-generate" && !flag_check
&& !flag_simcheck
&& !top_mod
) {
659 generate_mode
= true;
660 log("Entering generate mode.\n");
661 while (++argidx
< args
.size()) {
662 const char *p
= args
[argidx
].c_str();
663 generate_port_decl_t decl
;
664 if (p
[0] == 'i' && p
[1] == 'o')
665 decl
.input
= true, decl
.output
= true, p
+= 2;
667 decl
.input
= true, decl
.output
= false, p
++;
669 decl
.input
= false, decl
.output
= true, p
++;
674 decl
.index
= strtol(++p
, &endptr
, 10);
685 log("Port declaration: %s", decl
.input
? decl
.output
? "inout" : "input" : "output");
687 log(" [at position %d]", decl
.index
);
688 log(" %s\n", decl
.portname
.c_str());
689 generate_ports
.push_back(decl
);
692 log("Celltype: %s\n", args
[argidx
].c_str());
693 generate_cells
.push_back(RTLIL::unescape_id(args
[argidx
]));
697 if (args
[argidx
] == "-check") {
701 if (args
[argidx
] == "-simcheck") {
702 flag_simcheck
= true;
705 if (args
[argidx
] == "-purge_lib") {
709 if (args
[argidx
] == "-keep_positionals") {
710 keep_positionals
= true;
713 if (args
[argidx
] == "-keep_portwidths") {
714 keep_portwidths
= true;
717 if (args
[argidx
] == "-nodefaults") {
721 if (args
[argidx
] == "-nokeep_asserts") {
722 nokeep_asserts
= true;
725 if (args
[argidx
] == "-libdir" && argidx
+1 < args
.size()) {
726 libdirs
.push_back(args
[++argidx
]);
729 if (args
[argidx
] == "-top") {
730 if (++argidx
>= args
.size())
731 log_cmd_error("Option -top requires an additional argument!\n");
732 load_top_mod
= args
[argidx
];
735 if (args
[argidx
] == "-auto-top") {
736 auto_top_mode
= true;
739 if (args
[argidx
] == "-chparam" && argidx
+2 < args
.size()) {
740 const std::string
&key
= args
[++argidx
];
741 const std::string
&value
= args
[++argidx
];
742 auto r
= parameters
.emplace(key
, value
);
744 log_warning("-chparam %s already specified: overwriting.\n", key
.c_str());
745 r
.first
->second
= value
;
751 extra_args(args
, argidx
, design
, false);
753 if (!load_top_mod
.empty())
755 IdString top_name
= RTLIL::escape_id(load_top_mod
);
756 IdString abstract_id
= "$abstract" + RTLIL::escape_id(load_top_mod
);
757 top_mod
= design
->module(top_name
);
759 dict
<RTLIL::IdString
, RTLIL::Const
> top_parameters
;
760 for (auto ¶
: parameters
) {
762 if (!RTLIL::SigSpec::parse(sig_value
, NULL
, para
.second
))
763 log_cmd_error("Can't decode value '%s'!\n", para
.second
.c_str());
764 top_parameters
[RTLIL::escape_id(para
.first
)] = sig_value
.as_const();
767 if (top_mod
== nullptr && design
->module(abstract_id
))
768 top_mod
= design
->module(design
->module(abstract_id
)->derive(design
, top_parameters
));
769 else if (top_mod
!= nullptr && !top_parameters
.empty())
770 top_mod
= design
->module(top_mod
->derive(design
, top_parameters
));
772 if (top_mod
!= nullptr && top_mod
->name
!= top_name
) {
773 Module
*m
= top_mod
->clone();
775 Module
*old_mod
= design
->module(top_name
);
777 design
->remove(old_mod
);
783 if (top_mod
== nullptr && !load_top_mod
.empty()) {
784 #ifdef YOSYS_ENABLE_VERIFIC
785 if (verific_import_pending
) {
786 verific_import(design
, parameters
, load_top_mod
);
787 top_mod
= design
->module(RTLIL::escape_id(load_top_mod
));
791 log_cmd_error("Module `%s' not found!\n", load_top_mod
.c_str());
793 #ifdef YOSYS_ENABLE_VERIFIC
794 if (verific_import_pending
)
795 verific_import(design
, parameters
);
800 generate(design
, generate_cells
, generate_ports
);
806 if (top_mod
== nullptr)
807 for (auto &mod_it
: design
->modules_
)
808 if (mod_it
.second
->get_bool_attribute("\\top"))
809 top_mod
= mod_it
.second
;
811 if (top_mod
!= nullptr && top_mod
->name
.begins_with("$abstract")) {
812 IdString top_name
= top_mod
->name
.substr(strlen("$abstract"));
814 dict
<RTLIL::IdString
, RTLIL::Const
> top_parameters
;
815 for (auto ¶
: parameters
) {
817 if (!RTLIL::SigSpec::parse(sig_value
, NULL
, para
.second
))
818 log_cmd_error("Can't decode value '%s'!\n", para
.second
.c_str());
819 top_parameters
[RTLIL::escape_id(para
.first
)] = sig_value
.as_const();
822 top_mod
= design
->module(top_mod
->derive(design
, top_parameters
));
824 if (top_mod
!= nullptr && top_mod
->name
!= top_name
) {
825 Module
*m
= top_mod
->clone();
827 Module
*old_mod
= design
->module(top_name
);
829 design
->remove(old_mod
);
835 if (top_mod
== nullptr && auto_top_mode
) {
836 log_header(design
, "Finding top of design hierarchy..\n");
837 dict
<Module
*, int> db
;
838 for (Module
*mod
: design
->selected_modules()) {
839 int score
= find_top_mod_score(design
, mod
, db
);
840 log("root of %3d design levels: %-20s\n", score
, log_id(mod
));
841 if (!top_mod
|| score
> db
[top_mod
])
844 if (top_mod
!= nullptr)
845 log("Automatically selected %s as design top module.\n", log_id(top_mod
));
848 if (flag_simcheck
&& top_mod
== nullptr)
849 log_error("Design has no top module.\n");
851 if (top_mod
!= NULL
) {
852 for (auto &mod_it
: design
->modules_
)
853 if (mod_it
.second
== top_mod
)
854 mod_it
.second
->attributes
["\\initial_top"] = RTLIL::Const(1);
856 mod_it
.second
->attributes
.erase("\\initial_top");
859 bool did_something
= true;
860 while (did_something
)
862 did_something
= false;
864 std::set
<RTLIL::Module
*, IdString::compare_ptr_by_name
<Module
>> used_modules
;
865 if (top_mod
!= NULL
) {
866 log_header(design
, "Analyzing design hierarchy..\n");
867 hierarchy_worker(design
, used_modules
, top_mod
, 0);
869 for (auto mod
: design
->modules())
870 used_modules
.insert(mod
);
873 for (auto module
: used_modules
) {
874 if (expand_module(design
, module
, flag_check
, flag_simcheck
, libdirs
))
875 did_something
= true;
879 // The top module might have changed if interface instances have been detected in it:
880 RTLIL::Module
*tmp_top_mod
= check_if_top_has_changed(design
, top_mod
);
881 if (tmp_top_mod
!= NULL
) {
882 if (tmp_top_mod
!= top_mod
){
883 top_mod
= tmp_top_mod
;
884 did_something
= true;
888 // Delete modules marked as 'to_delete':
889 std::vector
<RTLIL::Module
*> modules_to_delete
;
890 for(auto &mod_it
: design
->modules_
) {
891 if (mod_it
.second
->get_bool_attribute("\\to_delete")) {
892 modules_to_delete
.push_back(mod_it
.second
);
895 for(size_t i
=0; i
<modules_to_delete
.size(); i
++) {
896 design
->remove(modules_to_delete
[i
]);
901 if (top_mod
!= NULL
) {
902 log_header(design
, "Analyzing design hierarchy..\n");
903 hierarchy_clean(design
, top_mod
, purge_lib
);
906 if (top_mod
!= NULL
) {
907 for (auto &mod_it
: design
->modules_
) {
908 if (mod_it
.second
== top_mod
)
909 mod_it
.second
->attributes
["\\top"] = RTLIL::Const(1);
911 mod_it
.second
->attributes
.erase("\\top");
912 mod_it
.second
->attributes
.erase("\\initial_top");
916 if (!nokeep_asserts
) {
917 std::map
<RTLIL::Module
*, bool> cache
;
918 for (auto mod
: design
->modules())
919 if (set_keep_assert(cache
, mod
)) {
920 log("Module %s directly or indirectly contains formal properties -> setting \"keep\" attribute.\n", log_id(mod
));
921 mod
->set_bool_attribute("\\keep");
925 if (!keep_positionals
)
927 std::set
<RTLIL::Module
*> pos_mods
;
928 std::map
<std::pair
<RTLIL::Module
*,int>, RTLIL::IdString
> pos_map
;
929 std::vector
<std::pair
<RTLIL::Module
*,RTLIL::Cell
*>> pos_work
;
931 for (auto &mod_it
: design
->modules_
)
932 for (auto &cell_it
: mod_it
.second
->cells_
) {
933 RTLIL::Cell
*cell
= cell_it
.second
;
934 if (design
->modules_
.count(cell
->type
) == 0)
936 for (auto &conn
: cell
->connections())
937 if (conn
.first
[0] == '$' && '0' <= conn
.first
[1] && conn
.first
[1] <= '9') {
938 pos_mods
.insert(design
->modules_
.at(cell
->type
));
939 pos_work
.push_back(std::pair
<RTLIL::Module
*,RTLIL::Cell
*>(mod_it
.second
, cell
));
944 for (auto module
: pos_mods
)
945 for (auto &wire_it
: module
->wires_
) {
946 RTLIL::Wire
*wire
= wire_it
.second
;
947 if (wire
->port_id
> 0)
948 pos_map
[std::pair
<RTLIL::Module
*,int>(module
, wire
->port_id
)] = wire
->name
;
951 for (auto &work
: pos_work
) {
952 RTLIL::Module
*module
= work
.first
;
953 RTLIL::Cell
*cell
= work
.second
;
954 log("Mapping positional arguments of cell %s.%s (%s).\n",
955 RTLIL::id2cstr(module
->name
), RTLIL::id2cstr(cell
->name
), RTLIL::id2cstr(cell
->type
));
956 dict
<RTLIL::IdString
, RTLIL::SigSpec
> new_connections
;
957 for (auto &conn
: cell
->connections())
958 if (conn
.first
[0] == '$' && '0' <= conn
.first
[1] && conn
.first
[1] <= '9') {
959 int id
= atoi(conn
.first
.c_str()+1);
960 std::pair
<RTLIL::Module
*,int> key(design
->modules_
.at(cell
->type
), id
);
961 if (pos_map
.count(key
) == 0) {
962 log(" Failed to map positional argument %d of cell %s.%s (%s).\n",
963 id
, RTLIL::id2cstr(module
->name
), RTLIL::id2cstr(cell
->name
), RTLIL::id2cstr(cell
->type
));
964 new_connections
[conn
.first
] = conn
.second
;
966 new_connections
[pos_map
.at(key
)] = conn
.second
;
968 new_connections
[conn
.first
] = conn
.second
;
969 cell
->connections_
= new_connections
;
975 dict
<IdString
, dict
<IdString
, Const
>> defaults_db
;
977 for (auto module
: design
->modules())
978 for (auto wire
: module
->wires())
979 if (wire
->port_input
&& wire
->attributes
.count("\\defaultvalue"))
980 defaults_db
[module
->name
][wire
->name
] = wire
->attributes
.at("\\defaultvalue");
982 for (auto module
: design
->modules())
983 for (auto cell
: module
->cells())
985 if (defaults_db
.count(cell
->type
) == 0)
988 if (keep_positionals
) {
989 bool found_positionals
= false;
990 for (auto &conn
: cell
->connections())
991 if (conn
.first
[0] == '$' && '0' <= conn
.first
[1] && conn
.first
[1] <= '9')
992 found_positionals
= true;
993 if (found_positionals
)
997 for (auto &it
: defaults_db
.at(cell
->type
))
998 if (!cell
->hasPort(it
.first
))
999 cell
->setPort(it
.first
, it
.second
);
1003 std::set
<Module
*> blackbox_derivatives
;
1004 std::vector
<Module
*> design_modules
= design
->modules();
1006 for (auto module
: design_modules
)
1008 pool
<Wire
*> wand_wor_index
;
1009 dict
<Wire
*, SigSpec
> wand_map
, wor_map
;
1010 vector
<SigSig
> new_connections
;
1012 for (auto wire
: module
->wires())
1014 if (wire
->get_bool_attribute("\\wand")) {
1015 wand_map
[wire
] = SigSpec();
1016 wand_wor_index
.insert(wire
);
1018 if (wire
->get_bool_attribute("\\wor")) {
1019 wor_map
[wire
] = SigSpec();
1020 wand_wor_index
.insert(wire
);
1024 for (auto &conn
: module
->connections())
1029 for (auto c
: conn
.first
.chunks())
1032 SigSpec rhs
= conn
.second
.extract(cursor
, GetSize(c
));
1034 if (wand_wor_index
.count(w
) == 0) {
1035 new_conn
.first
.append(c
);
1036 new_conn
.second
.append(rhs
);
1038 if (wand_map
.count(w
)) {
1039 SigSpec sig
= SigSpec(State::S1
, GetSize(w
));
1040 sig
.replace(c
.offset
, rhs
);
1041 wand_map
.at(w
).append(sig
);
1043 SigSpec sig
= SigSpec(State::S0
, GetSize(w
));
1044 sig
.replace(c
.offset
, rhs
);
1045 wor_map
.at(w
).append(sig
);
1048 cursor
+= GetSize(c
);
1050 new_connections
.push_back(new_conn
);
1052 module
->new_connections(new_connections
);
1054 for (auto cell
: module
->cells())
1059 for (auto &conn
: cell
->connections())
1061 if (!cell
->output(conn
.first
))
1065 bool update_port
= false;
1067 for (auto c
: conn
.second
.chunks())
1071 if (wand_wor_index
.count(w
) == 0) {
1076 Wire
*t
= module
->addWire(NEW_ID
, GetSize(c
));
1080 if (wand_map
.count(w
)) {
1081 SigSpec sig
= SigSpec(State::S1
, GetSize(w
));
1082 sig
.replace(c
.offset
, t
);
1083 wand_map
.at(w
).append(sig
);
1085 SigSpec sig
= SigSpec(State::S0
, GetSize(w
));
1086 sig
.replace(c
.offset
, t
);
1087 wor_map
.at(w
).append(sig
);
1092 cell
->setPort(conn
.first
, new_sig
);
1096 for (auto w
: wand_wor_index
)
1098 bool wand
= wand_map
.count(w
);
1099 SigSpec sigs
= wand
? wand_map
.at(w
) : wor_map
.at(w
);
1101 if (GetSize(sigs
) == 0)
1104 if (GetSize(w
) == 1) {
1106 module
->addReduceAnd(NEW_ID
, sigs
, w
);
1108 module
->addReduceOr(NEW_ID
, sigs
, w
);
1112 SigSpec s
= sigs
.extract(0, GetSize(w
));
1113 for (int i
= GetSize(w
); i
< GetSize(sigs
); i
+= GetSize(w
)) {
1115 s
= module
->And(NEW_ID
, s
, sigs
.extract(i
, GetSize(w
)));
1117 s
= module
->Or(NEW_ID
, s
, sigs
.extract(i
, GetSize(w
)));
1119 module
->connect(w
, s
);
1122 for (auto cell
: module
->cells())
1124 Module
*m
= design
->module(cell
->type
);
1129 if (m
->get_blackbox_attribute() && !cell
->parameters
.empty() && m
->get_bool_attribute("\\dynports")) {
1130 IdString new_m_name
= m
->derive(design
, cell
->parameters
, true);
1131 if (new_m_name
.empty())
1133 if (new_m_name
!= m
->name
) {
1134 m
= design
->module(new_m_name
);
1135 blackbox_derivatives
.insert(m
);
1139 for (auto &conn
: cell
->connections())
1141 Wire
*w
= m
->wire(conn
.first
);
1143 if (w
== nullptr || w
->port_id
== 0)
1146 if (GetSize(conn
.second
) == 0)
1149 SigSpec sig
= conn
.second
;
1151 if (!keep_portwidths
&& GetSize(w
) != GetSize(conn
.second
))
1153 if (GetSize(w
) < GetSize(conn
.second
))
1155 int n
= GetSize(conn
.second
) - GetSize(w
);
1156 if (!w
->port_input
&& w
->port_output
)
1157 module
->connect(sig
.extract(GetSize(w
), n
), Const(0, n
));
1158 sig
.remove(GetSize(w
), n
);
1162 int n
= GetSize(w
) - GetSize(conn
.second
);
1163 if (w
->port_input
&& !w
->port_output
)
1164 sig
.append(Const(0, n
));
1166 sig
.append(module
->addWire(NEW_ID
, n
));
1169 if (!conn
.second
.is_fully_const() || !w
->port_input
|| w
->port_output
)
1170 log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module
), log_id(cell
),
1171 log_id(conn
.first
), GetSize(conn
.second
), GetSize(sig
));
1172 cell
->setPort(conn
.first
, sig
);
1175 if (w
->port_output
&& !w
->port_input
&& sig
.has_const())
1176 log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
1177 log_id(module
), log_id(cell
), log_id(conn
.first
), log_id(cell
->type
), log_signal(sig
));
1182 for (auto module
: blackbox_derivatives
)
1183 design
->remove(module
);
1189 PRIVATE_NAMESPACE_END