Do not the 'z' modifier in format string (another win32 fix)
[yosys.git] / passes / hierarchy / hierarchy.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/yosys.h"
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <set>
24 #include <unistd.h>
25
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 struct generate_port_decl_t {
30 bool input, output;
31 RTLIL::IdString portname;
32 int index;
33 };
34
35 void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, const std::vector<generate_port_decl_t> &portdecls)
36 {
37 std::set<RTLIL::IdString> found_celltypes;
38
39 for (auto i1 : design->modules_)
40 for (auto i2 : i1.second->cells_)
41 {
42 RTLIL::Cell *cell = i2.second;
43 if (design->has(cell->type))
44 continue;
45 if (cell->type.substr(0, 1) == "$" && cell->type.substr(0, 3) != "$__")
46 continue;
47 for (auto &pattern : celltypes)
48 if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str()))
49 found_celltypes.insert(cell->type);
50 }
51
52 for (auto &celltype : found_celltypes)
53 {
54 std::set<RTLIL::IdString> portnames;
55 std::set<RTLIL::IdString> parameters;
56 std::map<RTLIL::IdString, int> portwidths;
57 log("Generate module for cell type %s:\n", celltype.c_str());
58
59 for (auto i1 : design->modules_)
60 for (auto i2 : i1.second->cells_)
61 if (i2.second->type == celltype) {
62 for (auto &conn : i2.second->connections()) {
63 if (conn.first[0] != '$')
64 portnames.insert(conn.first);
65 portwidths[conn.first] = std::max(portwidths[conn.first], conn.second.size());
66 }
67 for (auto &para : i2.second->parameters)
68 parameters.insert(para.first);
69 }
70
71 for (auto &decl : portdecls)
72 if (decl.index > 0)
73 portnames.insert(decl.portname);
74
75 std::set<int> indices;
76 for (int i = 0; i < int(portnames.size()); i++)
77 indices.insert(i+1);
78
79 std::vector<generate_port_decl_t> ports(portnames.size());
80
81 for (auto &decl : portdecls)
82 if (decl.index > 0) {
83 portwidths[decl.portname] = std::max(portwidths[decl.portname], 1);
84 portwidths[decl.portname] = std::max(portwidths[decl.portname], portwidths[stringf("$%d", decl.index)]);
85 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));
86 if (indices.count(decl.index) > ports.size())
87 log_error("Port index (%d) exceeds number of found ports (%d).\n", decl.index, int(ports.size()));
88 if (indices.count(decl.index) == 0)
89 log_error("Conflict on port index %d.\n", decl.index);
90 indices.erase(decl.index);
91 portnames.erase(decl.portname);
92 ports[decl.index-1] = decl;
93 }
94
95 while (portnames.size() > 0) {
96 RTLIL::IdString portname = *portnames.begin();
97 for (auto &decl : portdecls)
98 if (decl.index == 0 && patmatch(decl.portname.c_str(), RTLIL::unescape_id(portname).c_str())) {
99 generate_port_decl_t d = decl;
100 d.portname = portname;
101 d.index = *indices.begin();
102 log_assert(!indices.empty());
103 indices.erase(d.index);
104 ports[d.index-1] = d;
105 portwidths[d.portname] = std::max(portwidths[d.portname], 1);
106 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));
107 goto found_matching_decl;
108 }
109 log_error("Can't match port %s.\n", RTLIL::id2cstr(portname));
110 found_matching_decl:;
111 portnames.erase(portname);
112 }
113
114 log_assert(indices.empty());
115
116 RTLIL::Module *mod = new RTLIL::Module;
117 mod->name = celltype;
118 mod->attributes["\\blackbox"] = RTLIL::Const(1);
119 design->add(mod);
120
121 for (auto &decl : ports) {
122 RTLIL::Wire *wire = mod->addWire(decl.portname, portwidths.at(decl.portname));
123 wire->port_id = decl.index;
124 wire->port_input = decl.input;
125 wire->port_output = decl.output;
126 }
127
128 mod->fixup_ports();
129
130 for (auto &para : parameters)
131 log(" ignoring parameter %s.\n", RTLIL::id2cstr(para));
132
133 log(" module %s created.\n", RTLIL::id2cstr(mod->name));
134 }
135 }
136
137 bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
138 {
139 bool did_something = false;
140 std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
141 std::string filename;
142
143 for (auto &cell_it : module->cells_)
144 {
145 RTLIL::Cell *cell = cell_it.second;
146
147 if (cell->type.substr(0, 7) == "$array:") {
148 int pos_idx = cell->type.str().find_first_of(':');
149 int pos_num = cell->type.str().find_first_of(':', pos_idx + 1);
150 int pos_type = cell->type.str().find_first_of(':', pos_num + 1);
151 int idx = atoi(cell->type.str().substr(pos_idx + 1, pos_num).c_str());
152 int num = atoi(cell->type.str().substr(pos_num + 1, pos_type).c_str());
153 array_cells[cell] = std::pair<int, int>(idx, num);
154 cell->type = cell->type.str().substr(pos_type + 1);
155 }
156
157 if (design->modules_.count(cell->type) == 0)
158 {
159 if (design->modules_.count("$abstract" + cell->type.str()))
160 {
161 cell->type = design->modules_.at("$abstract" + cell->type.str())->derive(design, cell->parameters);
162 cell->parameters.clear();
163 did_something = true;
164 continue;
165 }
166
167 if (cell->type[0] == '$')
168 continue;
169
170 for (auto &dir : libdirs)
171 {
172 filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
173 if (access(filename.c_str(), F_OK) == 0) {
174 std::vector<std::string> args;
175 args.push_back(filename);
176 Frontend::frontend_call(design, NULL, filename, "verilog");
177 goto loaded_module;
178 }
179
180 filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
181 if (access(filename.c_str(), F_OK) == 0) {
182 std::vector<std::string> args;
183 args.push_back(filename);
184 Frontend::frontend_call(design, NULL, filename, "ilang");
185 goto loaded_module;
186 }
187 }
188
189 if (flag_check && cell->type[0] != '$')
190 log_error("Module `%s' referenced in module `%s' in cell `%s' is not part of the design.\n",
191 cell->type.c_str(), module->name.c_str(), cell->name.c_str());
192 continue;
193
194 loaded_module:
195 if (design->modules_.count(cell->type) == 0)
196 log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str());
197 did_something = true;
198 }
199
200 if (cell->parameters.size() == 0)
201 continue;
202
203 if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox"))
204 continue;
205
206 RTLIL::Module *mod = design->modules_[cell->type];
207 cell->type = mod->derive(design, cell->parameters);
208 cell->parameters.clear();
209 did_something = true;
210 }
211
212 for (auto &it : array_cells)
213 {
214 RTLIL::Cell *cell = it.first;
215 int idx = it.second.first, num = it.second.second;
216
217 if (design->modules_.count(cell->type) == 0)
218 log_error("Array cell `%s.%s' of unknown type `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
219
220 RTLIL::Module *mod = design->modules_[cell->type];
221
222 for (auto &conn : cell->connections_) {
223 int conn_size = conn.second.size();
224 RTLIL::IdString portname = conn.first;
225 if (portname.substr(0, 1) == "$") {
226 int port_id = atoi(portname.substr(1).c_str());
227 for (auto &wire_it : mod->wires_)
228 if (wire_it.second->port_id == port_id) {
229 portname = wire_it.first;
230 break;
231 }
232 }
233 if (mod->wires_.count(portname) == 0)
234 log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
235 int port_size = mod->wires_.at(portname)->width;
236 if (conn_size == port_size)
237 continue;
238 if (conn_size != port_size*num)
239 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));
240 conn.second = conn.second.extract(port_size*idx, port_size);
241 }
242 }
243
244 return did_something;
245 }
246
247 void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, int indent)
248 {
249 if (used.count(mod) > 0)
250 return;
251
252 if (indent == 0)
253 log("Top module: %s\n", mod->name.c_str());
254 else
255 log("Used module: %*s%s\n", indent, "", mod->name.c_str());
256 used.insert(mod);
257
258 for (auto &it : mod->cells_) {
259 if (design->modules_.count(it.second->type) > 0)
260 hierarchy_worker(design, used, design->modules_[it.second->type], indent+4);
261 }
262 }
263
264 void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib, bool first_pass)
265 {
266 std::set<RTLIL::Module*> used;
267 hierarchy_worker(design, used, top, 0);
268
269 std::vector<RTLIL::Module*> del_modules;
270 for (auto &it : design->modules_)
271 if (used.count(it.second) == 0)
272 del_modules.push_back(it.second);
273
274 for (auto mod : del_modules) {
275 if (first_pass && mod->name.substr(0, 9) == "$abstract")
276 continue;
277 if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
278 continue;
279 log("Removing unused module `%s'.\n", mod->name.c_str());
280 design->modules_.erase(mod->name);
281 delete mod;
282 }
283
284 log("Removed %d unused modules.\n", GetSize(del_modules));
285 }
286
287 bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
288 {
289 if (cache.count(mod) == 0)
290 for (auto c : mod->cells()) {
291 RTLIL::Module *m = mod->design->module(c->type);
292 if ((m != nullptr && set_keep_assert(cache, m)) || c->type == "$assert")
293 return cache[mod] = true;
294 }
295 return cache[mod];
296 }
297
298 struct HierarchyPass : public Pass {
299 HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
300 virtual void help()
301 {
302 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
303 log("\n");
304 log(" hierarchy [-check] [-top <module>]\n");
305 log(" hierarchy -generate <cell-types> <port-decls>\n");
306 log("\n");
307 log("In parametric designs, a module might exists in several variations with\n");
308 log("different parameter values. This pass looks at all modules in the current\n");
309 log("design an re-runs the language frontends for the parametric modules as\n");
310 log("needed.\n");
311 log("\n");
312 log(" -check\n");
313 log(" also check the design hierarchy. this generates an error when\n");
314 log(" an unknown module is used as cell type.\n");
315 log("\n");
316 log(" -purge_lib\n");
317 log(" by default the hierarchy command will not remove library (blackbox)\n");
318 log(" module. use this options to also remove unused blackbox modules.\n");
319 log("\n");
320 log(" -libdir <directory>\n");
321 log(" search for files named <module_name>.v in the specified directory\n");
322 log(" for unknown modules and automatically run read_verilog for each\n");
323 log(" unknown module.\n");
324 log("\n");
325 log(" -keep_positionals\n");
326 log(" per default this pass also converts positional arguments in cells\n");
327 log(" to arguments using port names. this option disables this behavior.\n");
328 log("\n");
329 log(" -nokeep_asserts\n");
330 log(" per default this pass sets the \"keep\" attribute on all modules\n");
331 log(" that directly or indirectly contain one or more $assert cells. this\n");
332 log(" option disables this behavior.\n");
333 log("\n");
334 log(" -top <module>\n");
335 log(" use the specified top module to built a design hierarchy. modules\n");
336 log(" outside this tree (unused modules) are removed.\n");
337 log("\n");
338 log(" when the -top option is used, the 'top' attribute will be set on the\n");
339 log(" specified top module. otherwise a module with the 'top' attribute set\n");
340 log(" will implicitly be used as top module, if such a module exists.\n");
341 log("\n");
342 log("In -generate mode this pass generates blackbox modules for the given cell\n");
343 log("types (wildcards supported). For this the design is searched for cells that\n");
344 log("match the given types and then the given port declarations are used to\n");
345 log("determine the direction of the ports. The syntax for a port declaration is:\n");
346 log("\n");
347 log(" {i|o|io}[@<num>]:<portname>\n");
348 log("\n");
349 log("Input ports are specified with the 'i' prefix, output ports with the 'o'\n");
350 log("prefix and inout ports with the 'io' prefix. The optional <num> specifies\n");
351 log("the position of the port in the parameter list (needed when instanciated\n");
352 log("using positional arguments). When <num> is not specified, the <portname> can\n");
353 log("also contain wildcard characters.\n");
354 log("\n");
355 log("This pass ignores the current selection and always operates on all modules\n");
356 log("in the current design.\n");
357 log("\n");
358 }
359 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
360 {
361 log_header("Executing HIERARCHY pass (managing design hierarchy).\n");
362
363 bool flag_check = false;
364 bool purge_lib = false;
365 RTLIL::Module *top_mod = NULL;
366 std::vector<std::string> libdirs;
367
368 bool generate_mode = false;
369 bool keep_positionals = false;
370 bool nokeep_asserts = false;
371 std::vector<std::string> generate_cells;
372 std::vector<generate_port_decl_t> generate_ports;
373
374 size_t argidx;
375 for (argidx = 1; argidx < args.size(); argidx++)
376 {
377 if (args[argidx] == "-generate" && !flag_check && !top_mod) {
378 generate_mode = true;
379 log("Entering generate mode.\n");
380 while (++argidx < args.size()) {
381 const char *p = args[argidx].c_str();
382 generate_port_decl_t decl;
383 if (p[0] == 'i' && p[1] == 'o')
384 decl.input = true, decl.output = true, p += 2;
385 else if (*p == 'i')
386 decl.input = true, decl.output = false, p++;
387 else if (*p == 'o')
388 decl.input = false, decl.output = true, p++;
389 else
390 goto is_celltype;
391 if (*p == '@') {
392 char *endptr;
393 decl.index = strtol(++p, &endptr, 10);
394 if (decl.index < 1)
395 goto is_celltype;
396 p = endptr;
397 } else
398 decl.index = 0;
399 if (*(p++) != ':')
400 goto is_celltype;
401 if (*p == 0)
402 goto is_celltype;
403 decl.portname = p;
404 log("Port declaration: %s", decl.input ? decl.output ? "inout" : "input" : "output");
405 if (decl.index >= 1)
406 log(" [at position %d]", decl.index);
407 log(" %s\n", decl.portname.c_str());
408 generate_ports.push_back(decl);
409 continue;
410 is_celltype:
411 log("Celltype: %s\n", args[argidx].c_str());
412 generate_cells.push_back(RTLIL::unescape_id(args[argidx]));
413 }
414 continue;
415 }
416 if (args[argidx] == "-check") {
417 flag_check = true;
418 continue;
419 }
420 if (args[argidx] == "-purge_lib") {
421 purge_lib = true;
422 continue;
423 }
424 if (args[argidx] == "-keep_positionals") {
425 keep_positionals = true;
426 continue;
427 }
428 if (args[argidx] == "-nokeep_asserts") {
429 nokeep_asserts = true;
430 continue;
431 }
432 if (args[argidx] == "-libdir" && argidx+1 < args.size()) {
433 libdirs.push_back(args[++argidx]);
434 continue;
435 }
436 if (args[argidx] == "-top") {
437 if (++argidx >= args.size())
438 log_cmd_error("Option -top requires an additional argument!\n");
439 top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
440 if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
441 std::map<RTLIL::IdString, RTLIL::Const> empty_parameters;
442 design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
443 top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
444 }
445 if (top_mod == NULL)
446 log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
447 continue;
448 }
449 break;
450 }
451 extra_args(args, argidx, design, false);
452
453 if (generate_mode) {
454 generate(design, generate_cells, generate_ports);
455 return;
456 }
457
458 log_push();
459
460 if (top_mod == NULL)
461 for (auto &mod_it : design->modules_)
462 if (mod_it.second->get_bool_attribute("\\top"))
463 top_mod = mod_it.second;
464
465 if (top_mod != NULL)
466 hierarchy(design, top_mod, purge_lib, true);
467
468 bool did_something = true;
469 bool did_something_once = false;
470 while (did_something) {
471 did_something = false;
472 std::vector<RTLIL::IdString> modnames;
473 modnames.reserve(design->modules_.size());
474 for (auto &mod_it : design->modules_)
475 modnames.push_back(mod_it.first);
476 for (auto &modname : modnames) {
477 if (design->modules_.count(modname) == 0)
478 continue;
479 if (expand_module(design, design->modules_[modname], flag_check, libdirs))
480 did_something = true;
481 }
482 if (did_something)
483 did_something_once = true;
484 }
485
486 if (top_mod != NULL && did_something_once) {
487 log_header("Re-running hierarchy analysis..\n");
488 hierarchy(design, top_mod, purge_lib, false);
489 }
490
491 if (top_mod != NULL) {
492 for (auto &mod_it : design->modules_)
493 if (mod_it.second == top_mod)
494 mod_it.second->attributes["\\top"] = RTLIL::Const(1);
495 else
496 mod_it.second->attributes.erase("\\top");
497 }
498
499 if (!nokeep_asserts) {
500 std::map<RTLIL::Module*, bool> cache;
501 for (auto mod : design->modules())
502 if (set_keep_assert(cache, mod)) {
503 log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod));
504 mod->set_bool_attribute("\\keep");
505 }
506 }
507
508 if (!keep_positionals)
509 {
510 std::set<RTLIL::Module*> pos_mods;
511 std::map<std::pair<RTLIL::Module*,int>, RTLIL::IdString> pos_map;
512 std::vector<std::pair<RTLIL::Module*,RTLIL::Cell*>> pos_work;
513
514 for (auto &mod_it : design->modules_)
515 for (auto &cell_it : mod_it.second->cells_) {
516 RTLIL::Cell *cell = cell_it.second;
517 if (design->modules_.count(cell->type) == 0)
518 continue;
519 for (auto &conn : cell->connections())
520 if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
521 pos_mods.insert(design->modules_.at(cell->type));
522 pos_work.push_back(std::pair<RTLIL::Module*,RTLIL::Cell*>(mod_it.second, cell));
523 break;
524 }
525 }
526
527 for (auto module : pos_mods)
528 for (auto &wire_it : module->wires_) {
529 RTLIL::Wire *wire = wire_it.second;
530 if (wire->port_id > 0)
531 pos_map[std::pair<RTLIL::Module*,int>(module, wire->port_id)] = wire->name;
532 }
533
534 for (auto &work : pos_work) {
535 RTLIL::Module *module = work.first;
536 RTLIL::Cell *cell = work.second;
537 log("Mapping positional arguments of cell %s.%s (%s).\n",
538 RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
539 std::map<RTLIL::IdString, RTLIL::SigSpec> new_connections;
540 for (auto &conn : cell->connections())
541 if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
542 int id = atoi(conn.first.c_str()+1);
543 std::pair<RTLIL::Module*,int> key(design->modules_.at(cell->type), id);
544 if (pos_map.count(key) == 0) {
545 log(" Failed to map positional argument %d of cell %s.%s (%s).\n",
546 id, RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
547 new_connections[conn.first] = conn.second;
548 } else
549 new_connections[pos_map.at(key)] = conn.second;
550 } else
551 new_connections[conn.first] = conn.second;
552 cell->connections_ = new_connections;
553 }
554 }
555
556 log_pop();
557 }
558 } HierarchyPass;
559
560 PRIVATE_NAMESPACE_END