Added CONSTMSK and CONSTVAL feature to techmap
[yosys.git] / passes / techmap / techmap.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/register.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/log.h"
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "passes/techmap/stdcells.inc"
29
30 // see simplemap.cc
31 extern void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
32
33 static void apply_prefix(std::string prefix, std::string &id)
34 {
35 if (id[0] == '\\')
36 id = prefix + "." + id.substr(1);
37 else
38 id = "$techmap" + prefix + "." + id;
39 }
40
41 static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
42 {
43 for (size_t i = 0; i < sig.chunks.size(); i++) {
44 if (sig.chunks[i].wire == NULL)
45 continue;
46 std::string wire_name = sig.chunks[i].wire->name;
47 apply_prefix(prefix, wire_name);
48 assert(module->wires.count(wire_name) > 0);
49 sig.chunks[i].wire = module->wires[wire_name];
50 }
51 }
52
53 struct TechmapWorker
54 {
55 std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers;
56 std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
57 std::map<RTLIL::Module*, bool> techmap_do_cache;
58
59 struct TechmapWireData {
60 RTLIL::Wire *wire;
61 RTLIL::SigSpec value;
62 };
63
64 typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires;
65
66 TechmapWires techmap_find_special_wires(RTLIL::Module *module)
67 {
68 TechmapWires result;
69
70 if (module == NULL)
71 return result;
72
73 for (auto &it : module->wires) {
74 const char *p = it.first.c_str();
75 if (*p == '$')
76 continue;
77
78 const char *q = strrchr(p+1, '.');
79 p = q ? q : p+1;
80
81 if (!strncmp(p, "_TECHMAP_", 9)) {
82 TechmapWireData record;
83 record.wire = it.second;
84 record.value = it.second;
85 result[p].push_back(record);
86 it.second->attributes["\\keep"] = RTLIL::Const(1);
87 it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1);
88 }
89 }
90
91 if (!result.empty()) {
92 SigMap sigmap(module);
93 for (auto &it1 : result)
94 for (auto &it2 : it1.second)
95 sigmap.apply(it2.value);
96 }
97
98 return result;
99 }
100
101 void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, bool flatten_mode)
102 {
103 log("Mapping `%s.%s' using `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(tpl->name));
104
105 if (tpl->memories.size() != 0)
106 log_error("Technology map yielded memories -> this is not supported.\n");
107
108 if (tpl->processes.size() != 0)
109 log_error("Technology map yielded processes -> this is not supported.\n");
110
111 std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
112
113 for (auto &it : tpl->wires) {
114 if (it.second->port_id > 0)
115 positional_ports[stringf("$%d", it.second->port_id)] = it.first;
116 RTLIL::Wire *w = new RTLIL::Wire(*it.second);
117 apply_prefix(cell->name, w->name);
118 w->port_input = false;
119 w->port_output = false;
120 w->port_id = 0;
121 if (it.second->get_bool_attribute("\\_techmap_special_"))
122 w->attributes.clear();
123 module->wires[w->name] = w;
124 design->select(module, w);
125 }
126
127 SigMap port_signal_map;
128
129 for (auto &it : cell->connections) {
130 RTLIL::IdString portname = it.first;
131 if (positional_ports.count(portname) > 0)
132 portname = positional_ports.at(portname);
133 if (tpl->wires.count(portname) == 0 || tpl->wires.at(portname)->port_id == 0) {
134 if (portname.substr(0, 1) == "$")
135 log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str());
136 continue;
137 }
138 RTLIL::Wire *w = tpl->wires.at(portname);
139 RTLIL::SigSig c;
140 if (w->port_output) {
141 c.first = it.second;
142 c.second = RTLIL::SigSpec(w);
143 apply_prefix(cell->name, c.second, module);
144 } else {
145 c.first = RTLIL::SigSpec(w);
146 c.second = it.second;
147 apply_prefix(cell->name, c.first, module);
148 }
149 if (c.second.width > c.first.width)
150 c.second.remove(c.first.width, c.second.width - c.first.width);
151 if (c.second.width < c.first.width)
152 c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.width - c.second.width));
153 assert(c.first.width == c.second.width);
154 #if 0
155 // more conservative approach:
156 // connect internal and external wires
157 module->connections.push_back(c);
158 #else
159 // approach that yields nicer outputs:
160 // replace internal wires that are connected to external wires
161 if (w->port_output)
162 port_signal_map.add(c.second, c.first);
163 else
164 port_signal_map.add(c.first, c.second);
165 #endif
166 }
167
168 for (auto &it : tpl->cells) {
169 RTLIL::Cell *c = new RTLIL::Cell(*it.second);
170 if (!flatten_mode && c->type.substr(0, 2) == "\\$")
171 c->type = c->type.substr(1);
172 apply_prefix(cell->name, c->name);
173 for (auto &it2 : c->connections) {
174 apply_prefix(cell->name, it2.second, module);
175 port_signal_map.apply(it2.second);
176 }
177 module->cells[c->name] = c;
178 design->select(module, c);
179 }
180
181 for (auto &it : tpl->connections) {
182 RTLIL::SigSig c = it;
183 apply_prefix(cell->name, c.first, module);
184 apply_prefix(cell->name, c.second, module);
185 port_signal_map.apply(c.first);
186 port_signal_map.apply(c.second);
187 module->connections.push_back(c);
188 }
189
190 module->cells.erase(cell->name);
191 delete cell;
192 }
193
194 bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells,
195 const std::map<RTLIL::IdString, std::set<RTLIL::IdString>> &celltypeMap, bool flatten_mode)
196 {
197 if (!design->selected(module))
198 return false;
199
200 bool log_continue = false;
201 bool did_something = false;
202 std::vector<std::string> cell_names;
203
204 SigMap sigmap(module);
205 for (auto &cell_it : module->cells)
206 cell_names.push_back(cell_it.first);
207
208 for (auto &cell_name : cell_names)
209 {
210 if (module->cells.count(cell_name) == 0)
211 continue;
212
213 RTLIL::Cell *cell = module->cells[cell_name];
214
215 if (!design->selected(module, cell) || handled_cells.count(cell) > 0)
216 continue;
217
218 if (celltypeMap.count(cell->type) == 0)
219 continue;
220
221 for (auto &tpl_name : celltypeMap.at(cell->type))
222 {
223 std::string derived_name = tpl_name;
224 RTLIL::Module *tpl = map->modules[tpl_name];
225 std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters;
226
227 if (!flatten_mode)
228 {
229 if (tpl->get_bool_attribute("\\techmap_simplemap")) {
230 log("Mapping %s.%s (%s) with simplemap.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
231 if (simplemap_mappers.count(cell->type) == 0)
232 log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type));
233 simplemap_mappers.at(cell->type)(module, cell);
234 module->cells.erase(cell->name);
235 delete cell;
236 cell = NULL;
237 did_something = true;
238 break;
239 }
240
241 for (auto conn : cell->connections) {
242 if (conn.first.substr(0, 1) == "$")
243 continue;
244 if (tpl->wires.count(conn.first) > 0 && tpl->wires.at(conn.first)->port_id > 0)
245 continue;
246 if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0)
247 goto next_tpl;
248 parameters[conn.first] = conn.second.as_const();
249 }
250
251 if (0) {
252 next_tpl:
253 continue;
254 }
255
256 if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0)
257 parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type);
258
259 for (auto conn : cell->connections) {
260 if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) {
261 std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
262 for (auto &bit : v)
263 bit = RTLIL::SigBit(bit.wire == NULL ? RTLIL::State::S1 : RTLIL::State::S0);
264 parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
265 }
266 if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))) != 0) {
267 std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
268 for (auto &bit : v)
269 if (bit.wire != NULL)
270 bit = RTLIL::SigBit(RTLIL::State::Sx);
271 parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
272 }
273 }
274 }
275
276 std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters);
277 if (techmap_cache.count(key) > 0) {
278 tpl = techmap_cache[key];
279 } else {
280 if (cell->parameters.size() != 0) {
281 derived_name = tpl->derive(map, parameters);
282 tpl = map->modules[derived_name];
283 log_continue = true;
284 }
285 techmap_cache[key] = tpl;
286 }
287
288 if (flatten_mode)
289 techmap_do_cache[tpl] = true;
290
291 if (techmap_do_cache.count(tpl) == 0)
292 {
293 bool keep_running = true;
294 techmap_do_cache[tpl] = true;
295
296 while (keep_running)
297 {
298 TechmapWires twd = techmap_find_special_wires(tpl);
299 keep_running = false;
300
301 for (auto &it : twd["_TECHMAP_FAIL_"]) {
302 RTLIL::SigSpec value = it.value;
303 if (value.is_fully_const() && value.as_bool()) {
304 log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n",
305 derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value));
306 techmap_do_cache[tpl] = false;
307 }
308 }
309
310 if (!techmap_do_cache[tpl])
311 break;
312
313 for (auto &it : twd)
314 {
315 if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty())
316 continue;
317
318 auto &data = it.second.front();
319
320 if (!data.value.is_fully_const())
321 log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value));
322
323 tpl->wires.erase(data.wire->name);
324 const char *p = data.wire->name.c_str();
325 const char *q = strrchr(p+1, '.');
326 q = q ? q : p+1;
327
328 assert(!strncmp(q, "_TECHMAP_DO_", 12));
329 std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12);
330 while (tpl->wires.count(new_name))
331 new_name += "_";
332 data.wire->name = new_name;
333 tpl->add(data.wire);
334
335 std::string cmd_string = data.value.as_const().decode_string();
336
337 RTLIL::Selection tpl_mod_sel(false);
338 tpl_mod_sel.select(tpl);
339 map->selection_stack.push_back(tpl_mod_sel);
340 Pass::call(map, cmd_string);
341 map->selection_stack.pop_back();
342
343 keep_running = true;
344 break;
345 }
346 }
347
348 TechmapWires twd = techmap_find_special_wires(tpl);
349 for (auto &it : twd) {
350 if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_")
351 log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str());
352 if (techmap_do_cache[tpl])
353 for (auto &it2 : it.second)
354 if (!it2.value.is_fully_const())
355 log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value));
356 }
357 }
358
359 if (techmap_do_cache.at(tpl) == false)
360 continue;
361
362 if (log_continue) {
363 log_header("Continuing TECHMAP pass.\n");
364 log_continue = false;
365 }
366
367 techmap_module_worker(design, module, cell, tpl, flatten_mode);
368 did_something = true;
369 cell = NULL;
370 break;
371 }
372
373 handled_cells.insert(cell);
374 }
375
376 if (log_continue) {
377 log_header("Continuing TECHMAP pass.\n");
378 log_continue = false;
379 }
380
381 return did_something;
382 }
383 };
384
385 struct TechmapPass : public Pass {
386 TechmapPass() : Pass("techmap", "generic technology mapper") { }
387 virtual void help()
388 {
389 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
390 log("\n");
391 log(" techmap [-map filename] [selection]\n");
392 log("\n");
393 log("This pass implements a very simple technology mapper that replaces cells in\n");
394 log("the design with implementations given in form of a verilog or ilang source\n");
395 log("file.\n");
396 log("\n");
397 log(" -map filename\n");
398 log(" the library of cell implementations to be used.\n");
399 log(" without this parameter a builtin library is used that\n");
400 log(" transforms the internal RTL cells to the internal gate\n");
401 log(" library.\n");
402 log("\n");
403 log(" -share_map filename\n");
404 log(" like -map, but look for the file in the share directory (where the\n");
405 log(" yosys data files are). this is mainly used internally when techmap\n");
406 log(" is called from other commands.\n");
407 log("\n");
408 log(" -D <define>, -I <incdir>\n");
409 log(" this options are passed as-is to the verilog frontend for loading the\n");
410 log(" map file. Note that the verilog frontend is also called with the\n");
411 log(" '-ignore_redef' option set.\n");
412 log("\n");
413 log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n");
414 log("match cells with a type that match the text value of this attribute. Otherwise\n");
415 log("the module name will be used to match the cell.\n");
416 log("\n");
417 log("When a module in the map file has the 'techmap_simplemap' attribute set, techmap\n");
418 log("will use 'simplemap' (see 'help simplemap') to map cells matching the module.\n");
419 log("\n");
420 log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n");
421 log("or *._TECHMAP_* are special wires that are used to pass instructions from\n");
422 log("the mapping module to the techmap command. At the moment the following special\n");
423 log("wires are supported:\n");
424 log("\n");
425 log(" _TECHMAP_FAIL_\n");
426 log(" When this wire is set to a non-zero constant value, techmap will not\n");
427 log(" use this module and instead try the next module with a matching\n");
428 log(" 'techmap_celltype' attribute.\n");
429 log("\n");
430 log(" When such a wire exists but does not have a constant value after all\n");
431 log(" _TECHMAP_DO_* commands have been executed, an error is generated.\n");
432 log("\n");
433 log(" _TECHMAP_DO_*\n");
434 log(" This wires are evaluated in alphabetical order. The constant text value\n");
435 log(" of this wire is a yosys command (or sequence of commands) that is run\n");
436 log(" by techmap on the module. A common use case is to run 'proc' on modules\n");
437 log(" that are written using always-statements.\n");
438 log("\n");
439 log(" When such a wire has a non-constant value at the time it is to be\n");
440 log(" evaluated, an error is produced. That means it is possible for such a\n");
441 log(" wire to start out as non-constant and evaluate to a constant value\n");
442 log(" during processing of other _TECHMAP_DO_* commands.\n");
443 log("\n");
444 log("In addition to this special wires, techmap also supports special parameters in\n");
445 log("modules in the map file:\n");
446 log("\n");
447 log(" _TECHMAP_CELLTYPE_\n");
448 log(" When a parameter with this name exists, it will be set to the type name\n");
449 log(" of the cell that matches the module.\n");
450 log("\n");
451 log(" _TECHMAP_CONSTMSK_<port-name>_\n");
452 log(" _TECHMAP_CONSTVAL_<port-name>_\n");
453 log(" When this pair of parameters is available in a module for a port, then\n");
454 log(" former has a 1-bit for each constant input bit and the latter has the\n");
455 log(" value for this bit. The unused bits of the latter are set to undef (x).\n");
456 log("\n");
457 log("When a module in the map file has a parameter where the according cell in the\n");
458 log("design has a port, the module from the map file is only used if the port in\n");
459 log("the design is connected to a constant value. The parameter is then set to the\n");
460 log("constant value.\n");
461 log("\n");
462 log("See 'help extract' for a pass that does the opposite thing.\n");
463 log("\n");
464 log("See 'help flatten' for a pass that does flatten the design (which is\n");
465 log("esentially techmap but using the design itself as map library).\n");
466 log("\n");
467 }
468 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
469 {
470 log_header("Executing TECHMAP pass (map to technology primitives).\n");
471 log_push();
472
473 std::vector<std::string> map_files;
474 std::string verilog_frontend = "verilog -ignore_redef";
475
476 size_t argidx;
477 for (argidx = 1; argidx < args.size(); argidx++) {
478 if (args[argidx] == "-map" && argidx+1 < args.size()) {
479 map_files.push_back(args[++argidx]);
480 continue;
481 }
482 if (args[argidx] == "-share_map" && argidx+1 < args.size()) {
483 map_files.push_back(get_share_file_name(args[++argidx]));
484 continue;
485 }
486 if (args[argidx] == "-D" && argidx+1 < args.size()) {
487 verilog_frontend += " -D " + args[++argidx];
488 continue;
489 }
490 if (args[argidx] == "-I" && argidx+1 < args.size()) {
491 verilog_frontend += " -I " + args[++argidx];
492 continue;
493 }
494 break;
495 }
496 extra_args(args, argidx, design);
497
498 TechmapWorker worker;
499 simplemap_get_mappers(worker.simplemap_mappers);
500
501 RTLIL::Design *map = new RTLIL::Design;
502 if (map_files.empty()) {
503 FILE *f = fmemopen(stdcells_code, strlen(stdcells_code), "rt");
504 Frontend::frontend_call(map, f, "<stdcells.v>", verilog_frontend);
505 fclose(f);
506 } else
507 for (auto &fn : map_files) {
508 FILE *f = fopen(fn.c_str(), "rt");
509 if (f == NULL)
510 log_cmd_error("Can't open map file `%s'\n", fn.c_str());
511 Frontend::frontend_call(map, f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
512 fclose(f);
513 }
514
515 std::map<RTLIL::IdString, RTLIL::Module*> modules_new;
516 for (auto &it : map->modules) {
517 if (it.first.substr(0, 2) == "\\$")
518 it.second->name = it.first.substr(1);
519 modules_new[it.second->name] = it.second;
520 }
521 map->modules.swap(modules_new);
522
523 std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap;
524 for (auto &it : map->modules) {
525 if (it.second->attributes.count("\\techmap_celltype") && !it.second->attributes.at("\\techmap_celltype").bits.empty()) {
526 char *p = strdup(it.second->attributes.at("\\techmap_celltype").decode_string().c_str());
527 for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n"))
528 celltypeMap[RTLIL::escape_id(q)].insert(it.first);
529 free(p);
530 } else
531 celltypeMap[it.first].insert(it.first);
532 }
533
534 bool did_something = true;
535 std::set<RTLIL::Cell*> handled_cells;
536 while (did_something) {
537 did_something = false;
538 for (auto &mod_it : design->modules)
539 if (worker.techmap_module(design, mod_it.second, map, handled_cells, celltypeMap, false))
540 did_something = true;
541 if (did_something)
542 design->check();
543 }
544
545 log("No more expansions possible.\n");
546 delete map;
547
548 log_pop();
549 }
550 } TechmapPass;
551
552 struct FlattenPass : public Pass {
553 FlattenPass() : Pass("flatten", "flatten design") { }
554 virtual void help()
555 {
556 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
557 log("\n");
558 log(" flatten [selection]\n");
559 log("\n");
560 log("This pass flattens the design by replacing cells by their implementation. This\n");
561 log("pass is very simmilar to the 'techmap' pass. The only difference is that this\n");
562 log("pass is using the current design as mapping library.\n");
563 log("\n");
564 }
565 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
566 {
567 log_header("Executing FLATTEN pass (flatten design).\n");
568 log_push();
569
570 extra_args(args, 1, design);
571
572 TechmapWorker worker;
573
574 std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap;
575 for (auto &it : design->modules)
576 celltypeMap[it.first].insert(it.first);
577
578 RTLIL::Module *top_mod = NULL;
579 if (design->full_selection())
580 for (auto &mod_it : design->modules)
581 if (mod_it.second->get_bool_attribute("\\top"))
582 top_mod = mod_it.second;
583
584 bool did_something = true;
585 std::set<RTLIL::Cell*> handled_cells;
586 while (did_something) {
587 did_something = false;
588 if (top_mod != NULL) {
589 if (worker.techmap_module(design, top_mod, design, handled_cells, celltypeMap, true))
590 did_something = true;
591 } else {
592 for (auto &mod_it : design->modules)
593 if (worker.techmap_module(design, mod_it.second, design, handled_cells, celltypeMap, true))
594 did_something = true;
595 }
596 }
597
598 log("No more expansions possible.\n");
599
600 if (top_mod != NULL) {
601 std::map<RTLIL::IdString, RTLIL::Module*> new_modules;
602 for (auto &mod_it : design->modules)
603 if (mod_it.second == top_mod) {
604 new_modules[mod_it.first] = mod_it.second;
605 } else {
606 log("Deleting now unused module %s.\n", RTLIL::id2cstr(mod_it.first));
607 delete mod_it.second;
608 }
609 design->modules.swap(new_modules);
610 }
611
612 log_pop();
613 }
614 } FlattenPass;
615