diff options
Diffstat (limited to 'passes/techmap/techmap.cc')
-rw-r--r-- | passes/techmap/techmap.cc | 1104 |
1 files changed, 798 insertions, 306 deletions
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index eeeebd111..ed466faa1 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -17,18 +17,22 @@ * */ -#include "kernel/register.h" +#include "kernel/yosys.h" +#include "kernel/utils.h" #include "kernel/sigtools.h" -#include "kernel/log.h" +#include "libs/sha1/sha1.h" + #include <stdlib.h> -#include <assert.h> #include <stdio.h> #include <string.h> -#include "passes/techmap/stdcells.inc" +#include "passes/techmap/techmap.inc" // see simplemap.cc -extern void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers); +extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers); + +// see maccmap.cc +extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false); static void apply_prefix(std::string prefix, std::string &id) { @@ -40,327 +44,712 @@ static void apply_prefix(std::string prefix, std::string &id) static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) { - for (size_t i = 0; i < sig.chunks.size(); i++) { - if (sig.chunks[i].wire == NULL) - continue; - std::string wire_name = sig.chunks[i].wire->name; - apply_prefix(prefix, wire_name); - assert(module->wires.count(wire_name) > 0); - sig.chunks[i].wire = module->wires[wire_name]; - } + std::vector<RTLIL::SigChunk> chunks = sig; + for (auto &chunk : chunks) + if (chunk.wire != NULL) { + std::string wire_name = chunk.wire->name.str(); + apply_prefix(prefix, wire_name); + log_assert(module->wires_.count(wire_name) > 0); + chunk.wire = module->wires_[wire_name]; + } + sig = chunks; } -std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers; -std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache; -std::map<RTLIL::Module*, bool> techmap_do_cache; - -struct TechmapWireData { - RTLIL::Wire *wire; - RTLIL::SigSpec value; -}; +struct TechmapWorker +{ + std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers; + std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache; + std::map<RTLIL::Module*, bool> techmap_do_cache; + std::set<RTLIL::Module*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Module>> module_queue; -typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires; + struct TechmapWireData { + RTLIL::Wire *wire; + RTLIL::SigSpec value; + }; -static TechmapWires techmap_find_special_wires(RTLIL::Module *module) -{ - TechmapWires result; + typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires; - if (module == NULL) - return result; + bool extern_mode; + bool assert_mode; + bool flatten_mode; + bool recursive_mode; + bool autoproc_mode; - for (auto &it : module->wires) { - const char *p = it.first.c_str(); - if (*p == '$') - continue; - - const char *q = strrchr(p+1, '.'); - p = q ? q : p+1; - - if (!strncmp(p, "_TECHMAP_", 9)) { - TechmapWireData record; - record.wire = it.second; - record.value = it.second; - result[p].push_back(record); - it.second->attributes["\\keep"] = RTLIL::Const(1); - it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1); - } + TechmapWorker() + { + extern_mode = false; + assert_mode = false; + flatten_mode = false; + recursive_mode = false; + autoproc_mode = false; } - if (!result.empty()) { - SigMap sigmap(module); - for (auto &it1 : result) - for (auto &it2 : it1.second) - sigmap.apply(it2.value); + std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose) + { + std::string constmap_info; + std::map<RTLIL::SigBit, std::pair<RTLIL::IdString, int>> connbits_map; + + for (auto conn : cell->connections()) + for (int i = 0; i < SIZE(conn.second); i++) { + RTLIL::SigBit bit = sigmap(conn.second[i]); + if (bit.wire == nullptr) { + if (verbose) + log(" Constant input on bit %d of port %s: %s\n", i, log_id(conn.first), log_signal(bit)); + constmap_info += stringf("|%s %d %d", log_id(conn.first), i, bit.data); + } else if (connbits_map.count(bit)) { + if (verbose) + log(" Bit %d of port %s and bit %d of port %s are connected.\n", i, log_id(conn.first), + connbits_map.at(bit).second, log_id(connbits_map.at(bit).first)); + constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, + log_id(connbits_map.at(bit).first), connbits_map.at(bit).second); + } else + connbits_map[bit] = std::pair<RTLIL::IdString, int>(conn.first, i);stringf("%s %d", log_id(conn.first), i, bit.data); + } + + return stringf("$paramod$constmap:%s%s", sha1(constmap_info).c_str(), tpl->name.c_str()); } - return result; -} + TechmapWires techmap_find_special_wires(RTLIL::Module *module) + { + TechmapWires result; -static void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, bool flatten_mode) -{ - log("Mapping `%s.%s' using `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(tpl->name)); - - if (tpl->memories.size() != 0) - log_error("Technology map yielded memories -> this is not supported.\n"); - - if (tpl->processes.size() != 0) - log_error("Technology map yielded processes -> this is not supported.\n"); - - std::map<RTLIL::IdString, RTLIL::IdString> positional_ports; - - for (auto &it : tpl->wires) { - if (it.second->port_id > 0) - positional_ports[stringf("$%d", it.second->port_id)] = it.first; - RTLIL::Wire *w = new RTLIL::Wire(*it.second); - apply_prefix(cell->name, w->name); - w->port_input = false; - w->port_output = false; - w->port_id = 0; - if (it.second->get_bool_attribute("\\_techmap_special_")) - w->attributes.clear(); - module->wires[w->name] = w; - design->select(module, w); - } + if (module == NULL) + return result; + + for (auto &it : module->wires_) { + const char *p = it.first.c_str(); + if (*p == '$') + continue; - SigMap port_signal_map; + const char *q = strrchr(p+1, '.'); + p = q ? q : p+1; - for (auto &it : cell->connections) { - RTLIL::IdString portname = it.first; - if (positional_ports.count(portname) > 0) - portname = positional_ports.at(portname); - if (tpl->wires.count(portname) == 0 || tpl->wires.at(portname)->port_id == 0) { - if (portname.substr(0, 1) == "$") - 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()); - continue; + if (!strncmp(p, "_TECHMAP_", 9)) { + TechmapWireData record; + record.wire = it.second; + record.value = it.second; + result[p].push_back(record); + it.second->attributes["\\keep"] = RTLIL::Const(1); + it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1); + } } - RTLIL::Wire *w = tpl->wires.at(portname); - RTLIL::SigSig c; - if (w->port_output) { - c.first = it.second; - c.second = RTLIL::SigSpec(w); - apply_prefix(cell->name, c.second, module); - } else { - c.first = RTLIL::SigSpec(w); - c.second = it.second; - apply_prefix(cell->name, c.first, module); + + if (!result.empty()) { + SigMap sigmap(module); + for (auto &it1 : result) + for (auto &it2 : it1.second) + sigmap.apply(it2.value); } - if (c.second.width > c.first.width) - c.second.remove(c.first.width, c.second.width - c.first.width); - if (c.second.width < c.first.width) - c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.width - c.second.width)); - assert(c.first.width == c.second.width); -#if 0 - // more conservative approach: - // connect internal and external wires - module->connections.push_back(c); -#else - // approach that yields nicer outputs: - // replace internal wires that are connected to external wires - if (w->port_output) - port_signal_map.add(c.second, c.first); - else - port_signal_map.add(c.first, c.second); -#endif + + return result; } - for (auto &it : tpl->cells) { - RTLIL::Cell *c = new RTLIL::Cell(*it.second); - if (!flatten_mode && c->type.substr(0, 2) == "\\$") - c->type = c->type.substr(1); - apply_prefix(cell->name, c->name); - for (auto &it2 : c->connections) { - apply_prefix(cell->name, it2.second, module); - port_signal_map.apply(it2.second); + void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl) + { + if (tpl->memories.size() != 0) + log_error("Technology map yielded memories -> this is not supported.\n"); + + if (tpl->processes.size() != 0) { + log("Technology map yielded processes:\n"); + for (auto &it : tpl->processes) + log(" %s",RTLIL::id2cstr(it.first)); + if (autoproc_mode) { + Pass::call_on_module(tpl->design, tpl, "proc"); + log_assert(SIZE(tpl->processes) == 0); + } else + log_error("Technology map yielded processes -> this is not supported (use -autoproc to run 'proc' automatically).\n"); } - module->cells[c->name] = c; - design->select(module, c); - } - for (auto &it : tpl->connections) { - RTLIL::SigSig c = it; - apply_prefix(cell->name, c.first, module); - apply_prefix(cell->name, c.second, module); - port_signal_map.apply(c.first); - port_signal_map.apply(c.second); - module->connections.push_back(c); - } + std::string orig_cell_name; + if (!flatten_mode) + for (auto &it : tpl->cells_) + if (it.first == "\\_TECHMAP_REPLACE_") { + orig_cell_name = cell->name.str(); + module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str()); + break; + } - module->cells.erase(cell->name); - delete cell; -} + std::map<RTLIL::IdString, RTLIL::IdString> positional_ports; + + for (auto &it : tpl->wires_) { + if (it.second->port_id > 0) + positional_ports[stringf("$%d", it.second->port_id)] = it.first; + std::string w_name = it.second->name.str(); + apply_prefix(cell->name.str(), w_name); + RTLIL::Wire *w = module->addWire(w_name, it.second); + w->port_input = false; + w->port_output = false; + w->port_id = 0; + if (it.second->get_bool_attribute("\\_techmap_special_")) + w->attributes.clear(); + design->select(module, w); + } -static bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells, - const std::map<RTLIL::IdString, std::set<RTLIL::IdString>> &celltypeMap, bool flatten_mode) -{ - if (!design->selected(module)) - return false; + SigMap port_signal_map; + + for (auto &it : cell->connections()) { + RTLIL::IdString portname = it.first; + if (positional_ports.count(portname) > 0) + portname = positional_ports.at(portname); + if (tpl->wires_.count(portname) == 0 || tpl->wires_.at(portname)->port_id == 0) { + if (portname.substr(0, 1) == "$") + 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()); + continue; + } + RTLIL::Wire *w = tpl->wires_.at(portname); + RTLIL::SigSig c; + if (w->port_output) { + c.first = it.second; + c.second = RTLIL::SigSpec(w); + apply_prefix(cell->name.str(), c.second, module); + } else { + c.first = RTLIL::SigSpec(w); + c.second = it.second; + apply_prefix(cell->name.str(), c.first, module); + } + if (c.second.size() > c.first.size()) + c.second.remove(c.first.size(), c.second.size() - c.first.size()); + if (c.second.size() < c.first.size()) + c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.size() - c.second.size())); + log_assert(c.first.size() == c.second.size()); + if (flatten_mode) { + // more conservative approach: + // connect internal and external wires + module->connect(c); + } else { + // approach that yields nicer outputs: + // replace internal wires that are connected to external wires + if (w->port_output) + port_signal_map.add(c.second, c.first); + else + port_signal_map.add(c.first, c.second); + } + } + + for (auto &it : tpl->cells_) + { + std::string c_name = it.second->name.str(); + + if (!flatten_mode && c_name == "\\_TECHMAP_REPLACE_") + c_name = orig_cell_name; + else + apply_prefix(cell->name.str(), c_name); + + RTLIL::Cell *c = module->addCell(c_name, it.second); + design->select(module, c); + + if (!flatten_mode && c->type.substr(0, 2) == "\\$") + c->type = c->type.substr(1); - bool log_continue = false; - bool did_something = false; - std::vector<std::string> cell_names; + for (auto &it2 : c->connections_) { + apply_prefix(cell->name.str(), it2.second, module); + port_signal_map.apply(it2.second); + } + } + + for (auto &it : tpl->connections()) { + RTLIL::SigSig c = it; + apply_prefix(cell->name.str(), c.first, module); + apply_prefix(cell->name.str(), c.second, module); + port_signal_map.apply(c.first); + port_signal_map.apply(c.second); + module->connect(c); + } - for (auto &cell_it : module->cells) - cell_names.push_back(cell_it.first); + module->remove(cell); + } - for (auto &cell_name : cell_names) + bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells, + const std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> &celltypeMap, bool in_recursion) { - if (module->cells.count(cell_name) == 0) - continue; + std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; + + if (!design->selected(module)) + return false; - RTLIL::Cell *cell = module->cells[cell_name]; + bool log_continue = false; + bool did_something = false; - if (!design->selected(module, cell) || handled_cells.count(cell) > 0) - continue; + SigMap sigmap(module); - if (celltypeMap.count(cell->type) == 0) - continue; + TopoSort<RTLIL::Cell*> cells; + std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit; + std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell; - for (auto &tpl_name : celltypeMap.at(cell->type)) + for (auto cell : module->cells()) { - std::string derived_name = tpl_name; - RTLIL::Module *tpl = map->modules[tpl_name]; - std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters; + if (!design->selected(module, cell) || handled_cells.count(cell) > 0) + continue; - if (!flatten_mode) - { - if (tpl->get_bool_attribute("\\techmap_simplemap")) { - log("Mapping %s.%s (%s) with simplemap.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); - if (simplemap_mappers.count(cell->type) == 0) - log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type)); - simplemap_mappers.at(cell->type)(module, cell); - module->cells.erase(cell->name); - delete cell; - cell = NULL; - did_something = true; - break; - } + std::string cell_type = cell->type.str(); + if (in_recursion && cell_type.substr(0, 2) == "\\$") + cell_type = cell_type.substr(1); - for (auto conn : cell->connections) { - if (conn.first.substr(0, 1) == "$") - continue; - if (tpl->wires.count(conn.first) > 0 && tpl->wires.at(conn.first)->port_id > 0) - continue; - if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0) - goto next_tpl; - parameters[conn.first] = conn.second.as_const(); - } + if (celltypeMap.count(cell_type) == 0) { + if (assert_mode && cell_type.back() != '_') + log_error("(ASSERT MODE) No matching template cell for type %s found.\n", log_id(cell_type)); + continue; + } - if (0) { - next_tpl: - continue; - } + for (auto &conn : cell->connections()) + { + RTLIL::SigSpec sig = sigmap(conn.second); + sig.remove_const(); - if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0) - parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type); - } + if (SIZE(sig) == 0) + continue; - std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters); - if (techmap_cache.count(key) > 0) { - tpl = techmap_cache[key]; - } else { - if (cell->parameters.size() != 0) { - derived_name = tpl->derive(map, parameters); - tpl = map->modules[derived_name]; - log_continue = true; + for (auto &tpl_name : celltypeMap.at(cell_type)) { + RTLIL::Module *tpl = map->modules_[tpl_name]; + RTLIL::Wire *port = tpl->wire(conn.first); + if (port && port->port_input) + cell_to_inbit[cell].insert(sig.begin(), sig.end()); + if (port && port->port_output) + for (auto &bit : sig) + outbit_to_cell[bit].insert(cell); } - techmap_cache[key] = tpl; } - if (flatten_mode) - techmap_do_cache[tpl] = true; + cells.node(cell); + } + + for (auto &it_right : cell_to_inbit) + for (auto &it_sigbit : it_right.second) + for (auto &it_left : outbit_to_cell[it_sigbit]) + cells.edge(it_left, it_right.first); + + cells.sort(); + + for (auto cell : cells.sorted) + { + log_assert(handled_cells.count(cell) == 0); + log_assert(cell == module->cell(cell->name)); + bool mapped_cell = false; + + std::string cell_type = cell->type.str(); + if (in_recursion && cell_type.substr(0, 2) == "\\$") + cell_type = cell_type.substr(1); - if (techmap_do_cache.count(tpl) == 0) + for (auto &tpl_name : celltypeMap.at(cell_type)) { - bool keep_running = true; - techmap_do_cache[tpl] = true; + RTLIL::IdString derived_name = tpl_name; + RTLIL::Module *tpl = map->modules_[tpl_name]; + std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters; + + if (tpl->get_bool_attribute("\\blackbox")) + continue; - while (keep_running) + if (!flatten_mode) { - TechmapWires twd = techmap_find_special_wires(tpl); - keep_running = false; - - for (auto &it : twd["_TECHMAP_FAIL_"]) { - RTLIL::SigSpec value = it.value; - if (value.is_fully_const() && value.as_bool()) { - log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", - derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value)); - techmap_do_cache[tpl] = false; + std::string extmapper_name; + + if (tpl->get_bool_attribute("\\techmap_simplemap")) + extmapper_name = "simplemap"; + + if (tpl->get_bool_attribute("\\techmap_maccmap")) + extmapper_name = "maccmap"; + + if (tpl->attributes.count("\\techmap_wrap")) + extmapper_name = "wrap"; + + if (!extmapper_name.empty()) + { + cell->type = cell_type; + + if ((extern_mode && !in_recursion) || extmapper_name == "wrap") + { + std::string m_name = stringf("$extern:%s:%s", extmapper_name.c_str(), log_id(cell->type)); + + for (auto &c : cell->parameters) + m_name += stringf(":%s=%s", log_id(c.first), log_signal(c.second)); + + if (extmapper_name == "wrap") + m_name += ":" + sha1(tpl->attributes.at("\\techmap_wrap").decode_string()); + + RTLIL::Design *extmapper_design = extern_mode && !in_recursion ? design : tpl->design; + RTLIL::Module *extmapper_module = extmapper_design->module(m_name); + + if (extmapper_module == nullptr) + { + extmapper_module = extmapper_design->addModule(m_name); + RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type, cell); + + int port_counter = 1; + for (auto &c : extmapper_cell->connections_) { + RTLIL::Wire *w = extmapper_module->addWire(c.first, SIZE(c.second)); + if (w->name == "\\Y" || w->name == "\\Q") + w->port_output = true; + else + w->port_input = true; + w->port_id = port_counter++; + c.second = w; + } + + extmapper_module->fixup_ports(); + extmapper_module->check(); + + if (extmapper_name == "simplemap") { + log("Creating %s with simplemap.\n", log_id(extmapper_module)); + if (simplemap_mappers.count(extmapper_cell->type) == 0) + log_error("No simplemap mapper for cell type %s found!\n", log_id(extmapper_cell->type)); + simplemap_mappers.at(extmapper_cell->type)(extmapper_module, extmapper_cell); + extmapper_module->remove(extmapper_cell); + } + + if (extmapper_name == "maccmap") { + log("Creating %s with maccmap.\n", log_id(extmapper_module)); + if (extmapper_cell->type != "$macc") + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(extmapper_cell->type)); + maccmap(extmapper_module, extmapper_cell); + extmapper_module->remove(extmapper_cell); + } + + if (extmapper_name == "wrap") { + std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string(); + log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module)); + Pass::call_on_module(extmapper_design, extmapper_module, cmd_string); + log_continue = true; + } + } + + cell->type = extmapper_module->name; + cell->parameters.clear(); + + if (!extern_mode || in_recursion) { + tpl = extmapper_module; + goto use_wrapper_tpl; + } + + log("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); + } + else + { + log("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); + + if (extmapper_name == "simplemap") { + if (simplemap_mappers.count(cell->type) == 0) + log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type)); + simplemap_mappers.at(cell->type)(module, cell); + } + + if (extmapper_name == "maccmap") { + if (cell->type != "$macc") + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(cell->type)); + maccmap(module, cell); + } + + module->remove(cell); + cell = NULL; } - } - if (!techmap_do_cache[tpl]) + did_something = true; + mapped_cell = true; break; + } - for (auto &it : twd) - { - if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty()) + for (auto conn : cell->connections()) { + if (conn.first.substr(0, 1) == "$") + continue; + if (tpl->wires_.count(conn.first) > 0 && tpl->wires_.at(conn.first)->port_id > 0) continue; + if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0) + goto next_tpl; + parameters[conn.first] = conn.second.as_const(); + } + + if (0) { + next_tpl: + continue; + } + + if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0) + parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type); + + for (auto conn : cell->connections()) { + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) { + std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector(); + for (auto &bit : v) + bit = RTLIL::SigBit(bit.wire == NULL ? RTLIL::State::S1 : RTLIL::State::S0); + parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); + } + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))) != 0) { + std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector(); + for (auto &bit : v) + if (bit.wire != NULL) + bit = RTLIL::SigBit(RTLIL::State::Sx); + parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); + } + } + + int unique_bit_id_counter = 0; + std::map<RTLIL::SigBit, int> unique_bit_id; + unique_bit_id[RTLIL::State::S0] = unique_bit_id_counter++; + unique_bit_id[RTLIL::State::S1] = unique_bit_id_counter++; + unique_bit_id[RTLIL::State::Sx] = unique_bit_id_counter++; + unique_bit_id[RTLIL::State::Sz] = unique_bit_id_counter++; + + for (auto conn : cell->connections()) + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) { + for (auto &bit : sigmap(conn.second).to_sigbit_vector()) + if (unique_bit_id.count(bit) == 0) + unique_bit_id[bit] = unique_bit_id_counter++; + } - auto &data = it.second.front(); + int bits = 0; + for (int i = 0; i < 32; i++) + if (((unique_bit_id_counter-1) & (1 << i)) != 0) + bits = i; + if (tpl->avail_parameters.count("\\_TECHMAP_BITS_CONNMAP_")) + parameters["\\_TECHMAP_BITS_CONNMAP_"] = bits; + + for (auto conn : cell->connections()) + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) { + RTLIL::Const value; + for (auto &bit : sigmap(conn.second).to_sigbit_vector()) { + RTLIL::Const chunk(unique_bit_id.at(bit), bits); + value.bits.insert(value.bits.end(), chunk.bits.begin(), chunk.bits.end()); + } + parameters[stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))] = value; + } + } - if (!data.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value)); + if (0) { + use_wrapper_tpl:; + // do not register techmap_wrap modules with techmap_cache + } else { + std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters); + if (techmap_cache.count(key) > 0) { + tpl = techmap_cache[key]; + } else { + if (cell->parameters.size() != 0) { + derived_name = tpl->derive(map, parameters); + tpl = map->module(derived_name); + log_continue = true; + } + techmap_cache[key] = tpl; + } + } - tpl->wires.erase(data.wire->name); - const char *p = data.wire->name.c_str(); - const char *q = strrchr(p+1, '.'); - q = q ? q : p+1; + if (flatten_mode) { + techmap_do_cache[tpl] = true; + } else { + RTLIL::Module *constmapped_tpl = map->module(constmap_tpl_name(sigmap, tpl, cell, false)); + if (constmapped_tpl != nullptr) + tpl = constmapped_tpl; + } - assert(!strncmp(q, "_TECHMAP_DO_", 12)); - std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12); - while (tpl->wires.count(new_name)) - new_name += "_"; - data.wire->name = new_name; - tpl->add(data.wire); + if (techmap_do_cache.count(tpl) == 0) + { + bool keep_running = true; + techmap_do_cache[tpl] = true; - std::string cmd_string = data.value.as_const().decode_string(); + std::set<std::string> techmap_wire_names; - RTLIL::Selection tpl_mod_sel(false); - tpl_mod_sel.select(tpl); - map->selection_stack.push_back(tpl_mod_sel); - Pass::call(map, cmd_string); - map->selection_stack.pop_back(); + while (keep_running) + { + TechmapWires twd = techmap_find_special_wires(tpl); + keep_running = false; + + for (auto &it : twd) + techmap_wire_names.insert(it.first); + + for (auto &it : twd["_TECHMAP_FAIL_"]) { + RTLIL::SigSpec value = it.value; + if (value.is_fully_const() && value.as_bool()) { + log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", + derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value)); + techmap_do_cache[tpl] = false; + } + } - keep_running = true; - break; + if (!techmap_do_cache[tpl]) + break; + + for (auto &it : twd) + { + if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty()) + continue; + + auto &data = it.second.front(); + + if (!data.value.is_fully_const()) + log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value)); + + techmap_wire_names.erase(it.first); + + const char *p = data.wire->name.c_str(); + const char *q = strrchr(p+1, '.'); + q = q ? q : p+1; + + std::string cmd_string = data.value.as_const().decode_string(); + + restart_eval_cmd_string: + if (cmd_string.rfind("CONSTMAP; ", 0) == 0) + { + cmd_string = cmd_string.substr(strlen("CONSTMAP; ")); + + log("Analyzing pattern of constant bits for this cell:\n"); + RTLIL::IdString new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true); + log("Creating constmapped module `%s'.\n", log_id(new_tpl_name)); + log_assert(map->module(new_tpl_name) == nullptr); + + RTLIL::Module *new_tpl = map->addModule(new_tpl_name); + tpl->cloneInto(new_tpl); + + techmap_do_cache.erase(tpl); + techmap_do_cache[new_tpl] = true; + tpl = new_tpl; + + std::map<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map; + std::map<RTLIL::SigBit, RTLIL::SigBit> port_connmap; + std::map<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits; + + for (auto wire : tpl->wires().to_vector()) + { + if (!wire->port_input || wire->port_output) + continue; + + RTLIL::IdString port_name = wire->name; + tpl->rename(wire, NEW_ID); + + RTLIL::Wire *new_wire = tpl->addWire(port_name, wire); + wire->port_input = false; + wire->port_id = 0; + + for (int i = 0; i < wire->width; i++) { + port_new2old_map[RTLIL::SigBit(new_wire, i)] = RTLIL::SigBit(wire, i); + port_connmap[RTLIL::SigBit(wire, i)] = RTLIL::SigBit(new_wire, i); + } + } + + for (auto conn : cell->connections()) + for (int i = 0; i < SIZE(conn.second); i++) + { + RTLIL::SigBit bit = sigmap(conn.second[i]); + RTLIL::SigBit tplbit(tpl->wire(conn.first), i); + + if (bit.wire == nullptr) + { + RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); + port_connmap.at(oldbit) = bit; + } + else if (cellbits_to_tplbits.count(bit)) + { + RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); + port_connmap.at(oldbit) = cellbits_to_tplbits[bit]; + } + else + cellbits_to_tplbits[bit] = tplbit; + } + + RTLIL::SigSig port_conn; + for (auto &it : port_connmap) { + port_conn.first.append_bit(it.first); + port_conn.second.append_bit(it.second); + } + tpl->connect(port_conn); + + tpl->check(); + goto restart_eval_cmd_string; + } + + if (cmd_string.rfind("RECURSION; ", 0) == 0) + { + cmd_string = cmd_string.substr(strlen("RECURSION; ")); + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } + goto restart_eval_cmd_string; + } + + Pass::call_on_module(map, tpl, cmd_string); + + log_assert(!strncmp(q, "_TECHMAP_DO_", 12)); + std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12); + while (tpl->wires_.count(new_name)) + new_name += "_"; + tpl->rename(data.wire->name, new_name); + + keep_running = true; + break; + } + } + + TechmapWires twd = techmap_find_special_wires(tpl); + for (auto &it : twd) { + if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") + log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str()); + if (techmap_do_cache[tpl]) + for (auto &it2 : it.second) + if (!it2.value.is_fully_const()) + log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value)); + techmap_wire_names.erase(it.first); + } + + for (auto &it : techmap_wire_names) + log_error("Techmap special wire %s disappeared. This is considered a fatal error.\n", RTLIL::id2cstr(it)); + + if (recursive_mode) { + if (log_continue) { + log_header("Continuing TECHMAP pass.\n"); + log_continue = false; + } + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } } } - TechmapWires twd = techmap_find_special_wires(tpl); - for (auto &it : twd) { - if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") - log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str()); - if (techmap_do_cache[tpl]) - for (auto &it2 : it.second) - if (!it2.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value)); + if (techmap_do_cache.at(tpl) == false) + continue; + + if (log_continue) { + log_header("Continuing TECHMAP pass.\n"); + log_continue = false; } - } - if (techmap_do_cache.at(tpl) == false) - continue; + if (extern_mode && !in_recursion) + { + std::string m_name = stringf("$extern:%s", log_id(tpl)); - if (log_continue) { - log_header("Continuing TECHMAP pass.\n"); - log_continue = false; + if (!design->module(m_name)) + { + RTLIL::Module *m = design->addModule(m_name); + tpl->cloneInto(m); + + for (auto cell : m->cells()) { + if (cell->type.substr(0, 2) == "\\$") + cell->type = cell->type.substr(1); + } + + module_queue.insert(m); + } + + log("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); + cell->type = m_name; + cell->parameters.clear(); + } + else + { + log("%s %s.%s using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(tpl)); + techmap_module_worker(design, module, cell, tpl); + cell = NULL; + } + did_something = true; + mapped_cell = true; + break; } - techmap_module_worker(design, module, cell, tpl, flatten_mode); - did_something = true; - cell = NULL; - break; + if (assert_mode && !mapped_cell) + log_error("(ASSERT MODE) Failed to map cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type)); + + handled_cells.insert(cell); } - handled_cells.insert(cell); - } + if (log_continue) { + log_header("Continuing TECHMAP pass.\n"); + log_continue = false; + } - if (log_continue) { - log_header("Continuing TECHMAP pass.\n"); - log_continue = false; + return did_something; } - - return did_something; -} +}; struct TechmapPass : public Pass { TechmapPass() : Pass("techmap", "generic technology mapper") { } @@ -380,11 +769,34 @@ struct TechmapPass : public Pass { log(" transforms the internal RTL cells to the internal gate\n"); log(" library.\n"); log("\n"); + log(" -map %%<design-name>\n"); + log(" like -map above, but with an in-memory design instead of a file.\n"); + log("\n"); log(" -share_map filename\n"); log(" like -map, but look for the file in the share directory (where the\n"); log(" yosys data files are). this is mainly used internally when techmap\n"); log(" is called from other commands.\n"); log("\n"); + log(" -extern\n"); + log(" load the cell implementations as separate modules into the design\n"); + log(" instead of inlining them.\n"); + log("\n"); + log(" -max_iter <number>\n"); + log(" only run the specified number of iterations.\n"); + log("\n"); + log(" -recursive\n"); + log(" instead of the iterative breadth-first algorithm use a recursive\n"); + log(" depth-first algorithm. both methods should yield equivialent results,\n"); + log(" but may differ in performance.\n"); + log("\n"); + log(" -autoproc\n"); + log(" Automatically call \"proc\" on implementations that contain processes.\n"); + log("\n"); + log(" -assert\n"); + log(" this option will cause techmap to exit with an error if it can't map\n"); + log(" a selected cell. only cell types that end on an underscore are accepted\n"); + log(" as final cell types by this mode.\n"); + log("\n"); log(" -D <define>, -I <incdir>\n"); log(" this options are passed as-is to the verilog frontend for loading the\n"); log(" map file. Note that the verilog frontend is also called with the\n"); @@ -397,6 +809,13 @@ struct TechmapPass : public Pass { log("When a module in the map file has the 'techmap_simplemap' attribute set, techmap\n"); log("will use 'simplemap' (see 'help simplemap') to map cells matching the module.\n"); log("\n"); + log("When a module in the map file has the 'techmap_maccmap' attribute set, techmap\n"); + log("will use 'maccmap' (see 'help maccmap') to map cells matching the module.\n"); + log("\n"); + log("When a module in the map file has the 'techmap_wrap' attribute set, techmap\n"); + log("will create a wrapper for the cell and then run the command string that the\n"); + log("attribute is set to on the wrapper module.\n"); + log("\n"); log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n"); log("or *._TECHMAP_* are special wires that are used to pass instructions from\n"); log("the mapping module to the techmap command. At the moment the following special\n"); @@ -421,6 +840,20 @@ struct TechmapPass : public Pass { log(" wire to start out as non-constant and evaluate to a constant value\n"); log(" during processing of other _TECHMAP_DO_* commands.\n"); log("\n"); + log(" A _TECHMAP_DO_* command may start with the special token 'CONSTMAP; '.\n"); + log(" in this case techmap will create a copy for each distinct configuration\n"); + log(" of constant inputs and shorted inputs at this point and import the\n"); + log(" constant and connected bits into the map module. All further commands\n"); + log(" are executed in this copy. This is a very convenient way of creating\n"); + log(" optimizied specializations of techmap modules without using the special\n"); + log(" parameters described below.\n"); + log("\n"); + log(" A _TECHMAP_DO_* command may start with the special token 'RECURSION; '.\n"); + log(" then techmap will recursively replace the cells in the module with their\n"); + log(" implementation. This is not affected by the -max_iter option.\n"); + log("\n"); + log(" It is possible to combine both prefixes to 'RECURSION; CONSTMAP; '.\n"); + log("\n"); log("In addition to this special wires, techmap also supports special parameters in\n"); log("modules in the map file:\n"); log("\n"); @@ -428,11 +861,28 @@ struct TechmapPass : public Pass { log(" When a parameter with this name exists, it will be set to the type name\n"); log(" of the cell that matches the module.\n"); log("\n"); + log(" _TECHMAP_CONSTMSK_<port-name>_\n"); + log(" _TECHMAP_CONSTVAL_<port-name>_\n"); + log(" When this pair of parameters is available in a module for a port, then\n"); + log(" former has a 1-bit for each constant input bit and the latter has the\n"); + log(" value for this bit. The unused bits of the latter are set to undef (x).\n"); + log("\n"); + log(" _TECHMAP_BITS_CONNMAP_\n"); + log(" _TECHMAP_CONNMAP_<port-name>_\n"); + log(" For an N-bit port, the _TECHMAP_CONNMAP_<port-name>_ parameter, if it\n"); + log(" exists, will be set to an N*_TECHMAP_BITS_CONNMAP_ bit vector containing\n"); + log(" N words (of _TECHMAP_BITS_CONNMAP_ bits each) that assign each single\n"); + log(" bit driver a unique id. The values 0-3 are reserved for 0, 1, x, and z.\n"); + log(" This can be used to detect shorted inputs.\n"); + log("\n"); log("When a module in the map file has a parameter where the according cell in the\n"); log("design has a port, the module from the map file is only used if the port in\n"); log("the design is connected to a constant value. The parameter is then set to the\n"); log("constant value.\n"); log("\n"); + log("A cell with the name _TECHMAP_REPLACE_ in the map file will inherit the name\n"); + log("of the cell that is beeing replaced.\n"); + log("\n"); log("See 'help extract' for a pass that does the opposite thing.\n"); log("\n"); log("See 'help flatten' for a pass that does flatten the design (which is\n"); @@ -444,17 +894,28 @@ struct TechmapPass : public Pass { log_header("Executing TECHMAP pass (map to technology primitives).\n"); log_push(); + TechmapWorker worker; + simplemap_get_mappers(worker.simplemap_mappers); + std::vector<std::string> map_files; std::string verilog_frontend = "verilog -ignore_redef"; + int max_iter = -1; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-map" && argidx+1 < args.size()) { - map_files.push_back(args[++argidx]); + if (args[argidx+1].substr(0, 2) == "+/") + map_files.push_back(proc_share_dirname() + args[++argidx].substr(2)); + else + map_files.push_back(args[++argidx]); continue; } if (args[argidx] == "-share_map" && argidx+1 < args.size()) { - map_files.push_back(get_share_file_name(args[++argidx])); + map_files.push_back(proc_share_dirname() + args[++argidx]); + continue; + } + if (args[argidx] == "-max_iter" && argidx+1 < args.size()) { + max_iter = atoi(args[++argidx].c_str()); continue; } if (args[argidx] == "-D" && argidx+1 < args.size()) { @@ -465,36 +926,58 @@ struct TechmapPass : public Pass { verilog_frontend += " -I " + args[++argidx]; continue; } + if (args[argidx] == "-assert") { + worker.assert_mode = true; + continue; + } + if (args[argidx] == "-extern") { + worker.extern_mode = true; + continue; + } + if (args[argidx] == "-recursive") { + worker.recursive_mode = true; + continue; + } + if (args[argidx] == "-autoproc") { + worker.autoproc_mode = true; + continue; + } break; } extra_args(args, argidx, design); - simplemap_get_mappers(simplemap_mappers); - RTLIL::Design *map = new RTLIL::Design; if (map_files.empty()) { - FILE *f = fmemopen(stdcells_code, strlen(stdcells_code), "rt"); - Frontend::frontend_call(map, f, "<stdcells.v>", verilog_frontend); - fclose(f); + std::istringstream f(stdcells_code); + Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend); } else - for (auto &fn : map_files) { - FILE *f = fopen(fn.c_str(), "rt"); - if (f == NULL) - log_cmd_error("Can't open map file `%s'\n", fn.c_str()); - Frontend::frontend_call(map, f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend); - fclose(f); - } + for (auto &fn : map_files) + if (fn.substr(0, 1) == "%") { + if (!saved_designs.count(fn.substr(1))) { + delete map; + log_cmd_error("Can't saved design `%s'.\n", fn.c_str()+1); + } + for (auto mod : saved_designs.at(fn.substr(1))->modules()) + if (!map->has(mod->name)) + map->add(mod->clone()); + } else { + std::ifstream f; + f.open(fn.c_str()); + if (f.fail()) + log_cmd_error("Can't open map file `%s'\n", fn.c_str()); + Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend); + } std::map<RTLIL::IdString, RTLIL::Module*> modules_new; - for (auto &it : map->modules) { + for (auto &it : map->modules_) { if (it.first.substr(0, 2) == "\\$") it.second->name = it.first.substr(1); modules_new[it.second->name] = it.second; } - map->modules.swap(modules_new); + map->modules_.swap(modules_new); - std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap; - for (auto &it : map->modules) { + std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; + for (auto &it : map->modules_) { if (it.second->attributes.count("\\techmap_celltype") && !it.second->attributes.at("\\techmap_celltype").bits.empty()) { char *p = strdup(it.second->attributes.at("\\techmap_celltype").decode_string().c_str()); for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n")) @@ -504,22 +987,30 @@ struct TechmapPass : public Pass { celltypeMap[it.first].insert(it.first); } - bool did_something = true; - std::set<RTLIL::Cell*> handled_cells; - while (did_something) { - did_something = false; - for (auto &mod_it : design->modules) - if (techmap_module(design, mod_it.second, map, handled_cells, celltypeMap, false)) - did_something = true; - if (did_something) - design->check(); + for (auto module : design->modules()) + worker.module_queue.insert(module); + + while (!worker.module_queue.empty()) + { + RTLIL::Module *module = *worker.module_queue.begin(); + worker.module_queue.erase(module); + + bool did_something = true; + std::set<RTLIL::Cell*> handled_cells; + while (did_something) { + did_something = false; + if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) + did_something = true; + if (did_something) + module->check(); + if (max_iter > 0 && --max_iter == 0) + break; + } } log("No more expansions possible.\n"); - techmap_cache.clear(); - techmap_do_cache.clear(); - simplemap_mappers.clear(); delete map; + log_pop(); } } TechmapPass; @@ -544,26 +1035,29 @@ struct FlattenPass : public Pass { extra_args(args, 1, design); - std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap; - for (auto &it : design->modules) + TechmapWorker worker; + worker.flatten_mode = true; + + std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; + for (auto &it : design->modules_) celltypeMap[it.first].insert(it.first); RTLIL::Module *top_mod = NULL; if (design->full_selection()) - for (auto &mod_it : design->modules) - if (mod_it.second->get_bool_attribute("\\top")) - top_mod = mod_it.second; + for (auto mod : design->modules()) + if (mod->get_bool_attribute("\\top")) + top_mod = mod; bool did_something = true; std::set<RTLIL::Cell*> handled_cells; while (did_something) { did_something = false; if (top_mod != NULL) { - if (techmap_module(design, top_mod, design, handled_cells, celltypeMap, true)) + if (worker.techmap_module(design, top_mod, design, handled_cells, celltypeMap, false)) did_something = true; } else { - for (auto &mod_it : design->modules) - if (techmap_module(design, mod_it.second, design, handled_cells, celltypeMap, true)) + for (auto mod : design->modules()) + if (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) did_something = true; } } @@ -572,18 +1066,16 @@ struct FlattenPass : public Pass { if (top_mod != NULL) { std::map<RTLIL::IdString, RTLIL::Module*> new_modules; - for (auto &mod_it : design->modules) - if (mod_it.second == top_mod) { - new_modules[mod_it.first] = mod_it.second; + for (auto mod : design->modules()) + if (mod == top_mod || mod->get_bool_attribute("\\blackbox")) { + new_modules[mod->name] = mod; } else { - log("Deleting now unused module %s.\n", RTLIL::id2cstr(mod_it.first)); - delete mod_it.second; + log("Deleting now unused module %s.\n", log_id(mod)); + delete mod; } - design->modules.swap(new_modules); + design->modules_.swap(new_modules); } - techmap_cache.clear(); - techmap_do_cache.clear(); log_pop(); } } FlattenPass; |