From: Clifford Wolf Date: Sun, 16 Feb 2014 16:16:44 +0000 (+0100) Subject: Added recursion support to techmap X-Git-Tag: yosys-0.3.0~149 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d3dc22a90f8b87ffe0109b0fa2074d887642e7cb;p=yosys.git Added recursion support to techmap --- diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index eeeebd111..eb044d6fe 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -50,317 +50,320 @@ static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module } } -std::map simplemap_mappers; -std::map>, RTLIL::Module*> techmap_cache; -std::map techmap_do_cache; +struct TechmapWorker +{ + std::map simplemap_mappers; + std::map>, RTLIL::Module*> techmap_cache; + std::map techmap_do_cache; -struct TechmapWireData { - RTLIL::Wire *wire; - RTLIL::SigSpec value; -}; + struct TechmapWireData { + RTLIL::Wire *wire; + RTLIL::SigSpec value; + }; -typedef std::map> TechmapWires; + typedef std::map> TechmapWires; -static TechmapWires techmap_find_special_wires(RTLIL::Module *module) -{ - TechmapWires result; + TechmapWires techmap_find_special_wires(RTLIL::Module *module) + { + TechmapWires result; - if (module == NULL) - return result; + if (module == NULL) + return result; - for (auto &it : module->wires) { - const char *p = it.first.c_str(); - if (*p == '$') - continue; + 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; + 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); + 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); + } } - } - if (!result.empty()) { - SigMap sigmap(module); - for (auto &it1 : result) - for (auto &it2 : it1.second) - sigmap.apply(it2.value); - } - - return result; -} + if (!result.empty()) { + SigMap sigmap(module); + for (auto &it1 : result) + for (auto &it2 : it1.second) + sigmap.apply(it2.value); + } -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 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); + return result; } - 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, c.second, module); - } else { - c.first = RTLIL::SigSpec(w); - c.second = it.second; - apply_prefix(cell->name, c.first, module); + 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 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 (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); + + 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, c.second, module); + } else { + c.first = RTLIL::SigSpec(w); + c.second = it.second; + apply_prefix(cell->name, c.first, module); + } + 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); + // 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); + // 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 - } + } + + 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); + } + module->cells[c->name] = c; + design->select(module, c); + } - 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); + 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); } - 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); + module->cells.erase(cell->name); + delete cell; } - module->cells.erase(cell->name); - delete cell; -} + bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set &handled_cells, + const std::map> &celltypeMap, bool flatten_mode) + { + if (!design->selected(module)) + return false; -static bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set &handled_cells, - const std::map> &celltypeMap, bool flatten_mode) -{ - if (!design->selected(module)) - return false; + bool log_continue = false; + bool did_something = false; + std::vector cell_names; - bool log_continue = false; - bool did_something = false; - std::vector cell_names; + for (auto &cell_it : module->cells) + cell_names.push_back(cell_it.first); - for (auto &cell_it : module->cells) - cell_names.push_back(cell_it.first); + for (auto &cell_name : cell_names) + { + if (module->cells.count(cell_name) == 0) + continue; - for (auto &cell_name : cell_names) - { - if (module->cells.count(cell_name) == 0) - continue; + RTLIL::Cell *cell = module->cells[cell_name]; - RTLIL::Cell *cell = module->cells[cell_name]; + if (!design->selected(module, cell) || handled_cells.count(cell) > 0) + continue; - if (!design->selected(module, cell) || handled_cells.count(cell) > 0) - continue; + if (celltypeMap.count(cell->type) == 0) + continue; - if (celltypeMap.count(cell->type) == 0) - continue; + for (auto &tpl_name : celltypeMap.at(cell->type)) + { + std::string derived_name = tpl_name; + RTLIL::Module *tpl = map->modules[tpl_name]; + std::map parameters = cell->parameters; - for (auto &tpl_name : celltypeMap.at(cell->type)) - { - std::string derived_name = tpl_name; - RTLIL::Module *tpl = map->modules[tpl_name]; - std::map parameters = cell->parameters; + 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; + } - 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; - } + 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(); + } - 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) + if (0) { + next_tpl: 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); } - if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0) - parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type); - } - - std::pair> 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; + std::pair> 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; + } + techmap_cache[key] = tpl; } - techmap_cache[key] = tpl; - } - - if (flatten_mode) - techmap_do_cache[tpl] = true; - if (techmap_do_cache.count(tpl) == 0) - { - bool keep_running = true; - techmap_do_cache[tpl] = true; + if (flatten_mode) + techmap_do_cache[tpl] = true; - while (keep_running) + if (techmap_do_cache.count(tpl) == 0) { - 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; + bool keep_running = true; + techmap_do_cache[tpl] = true; + + while (keep_running) + { + 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; + } } - } - if (!techmap_do_cache[tpl]) - break; + if (!techmap_do_cache[tpl]) + break; - for (auto &it : twd) - { - if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty()) - continue; + for (auto &it : twd) + { + if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty()) + continue; - auto &data = it.second.front(); + 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)); + 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)); - 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; + 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; - 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); + 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); - std::string cmd_string = data.value.as_const().decode_string(); + std::string cmd_string = data.value.as_const().decode_string(); - 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(); + 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(); - keep_running = true; - break; + 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)); + 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 (techmap_do_cache.at(tpl) == false) + continue; + + if (log_continue) { + log_header("Continuing TECHMAP pass.\n"); + log_continue = false; + } - if (log_continue) { - log_header("Continuing TECHMAP pass.\n"); - log_continue = false; + techmap_module_worker(design, module, cell, tpl, flatten_mode); + did_something = true; + cell = NULL; + break; } - techmap_module_worker(design, module, cell, tpl, flatten_mode); - did_something = true; - cell = NULL; - break; + 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") { } @@ -469,7 +472,8 @@ struct TechmapPass : public Pass { } extra_args(args, argidx, design); - simplemap_get_mappers(simplemap_mappers); + TechmapWorker worker; + simplemap_get_mappers(worker.simplemap_mappers); RTLIL::Design *map = new RTLIL::Design; if (map_files.empty()) { @@ -509,17 +513,15 @@ struct TechmapPass : public Pass { while (did_something) { did_something = false; for (auto &mod_it : design->modules) - if (techmap_module(design, mod_it.second, map, handled_cells, celltypeMap, false)) + if (worker.techmap_module(design, mod_it.second, map, handled_cells, celltypeMap, false)) did_something = true; if (did_something) design->check(); } log("No more expansions possible.\n"); - techmap_cache.clear(); - techmap_do_cache.clear(); - simplemap_mappers.clear(); delete map; + log_pop(); } } TechmapPass; @@ -544,6 +546,8 @@ struct FlattenPass : public Pass { extra_args(args, 1, design); + TechmapWorker worker; + std::map> celltypeMap; for (auto &it : design->modules) celltypeMap[it.first].insert(it.first); @@ -559,11 +563,11 @@ struct FlattenPass : public Pass { 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, true)) did_something = true; } else { for (auto &mod_it : design->modules) - if (techmap_module(design, mod_it.second, design, handled_cells, celltypeMap, true)) + if (worker.techmap_module(design, mod_it.second, design, handled_cells, celltypeMap, true)) did_something = true; } } @@ -582,8 +586,6 @@ struct FlattenPass : public Pass { design->modules.swap(new_modules); } - techmap_cache.clear(); - techmap_do_cache.clear(); log_pop(); } } FlattenPass;