diff options
Diffstat (limited to 'passes/techmap/techmap.cc')
-rw-r--r-- | passes/techmap/techmap.cc | 179 |
1 files changed, 97 insertions, 82 deletions
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index f98d1564a..5cd78fe28 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,6 +20,7 @@ #include "kernel/yosys.h" #include "kernel/utils.h" #include "kernel/sigtools.h" +#include "kernel/ffinit.h" #include "libs/sha1/sha1.h" #include <stdlib.h> @@ -117,19 +118,14 @@ struct TechmapWorker return result; for (auto w : module->wires()) { - const char *p = w->name.c_str(); - if (*p == '$') + if (*w->name.c_str() == '$') continue; - const char *q = strrchr(p+1, '.'); - if (q) - p = q; - - if (!strncmp(p, "\\_TECHMAP_", 10)) { + if (w->name.contains("_TECHMAP_") && !w->name.contains("_TECHMAP_REPLACE_")) { TechmapWireData record; record.wire = w; record.value = w; - result[p].push_back(record); + result[w->name].push_back(record); w->set_bool_attribute(ID::keep); w->set_bool_attribute(ID::_techmap_special_); } @@ -164,7 +160,7 @@ struct TechmapWorker orig_cell_name = cell->name.str(); for (auto tpl_cell : tpl->cells()) - if (tpl_cell->name == ID::_TECHMAP_REPLACE_) { + if (tpl_cell->name.ends_with("_TECHMAP_REPLACE_")) { module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str()); break; } @@ -225,23 +221,21 @@ struct TechmapWorker } design->select(module, w); - if (tpl_w->name.begins_with("\\_TECHMAP_REPLACE_.")) { - IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), tpl_w->name.c_str() + strlen("\\_TECHMAP_REPLACE_")); + if (const char *p = strstr(tpl_w->name.c_str(), "_TECHMAP_REPLACE_.")) { + IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), p + strlen("_TECHMAP_REPLACE_")); Wire *replace_w = module->addWire(replace_name, tpl_w); module->connect(replace_w, w); } } - SigMap tpl_sigmap(tpl); pool<SigBit> tpl_written_bits; - for (auto tpl_cell : tpl->cells()) for (auto &conn : tpl_cell->connections()) if (tpl_cell->output(conn.first)) - for (auto bit : tpl_sigmap(conn.second)) + for (auto bit : conn.second) tpl_written_bits.insert(bit); for (auto &conn : tpl->connections()) - for (auto bit : tpl_sigmap(conn.first)) + for (auto bit : conn.first) tpl_written_bits.insert(bit); SigMap port_signal_map; @@ -279,7 +273,7 @@ struct TechmapWorker SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second; apply_prefix(cell->name, sig_tpl_pf, module); for (int i = 0; i < GetSize(sig_tpl) && i < GetSize(sig_mod); i++) { - if (tpl_written_bits.count(tpl_sigmap(sig_tpl[i]))) { + if (tpl_written_bits.count(sig_tpl[i])) { c.first.append(sig_mod[i]); c.second.append(sig_tpl_pf[i]); } else { @@ -328,12 +322,12 @@ struct TechmapWorker for (auto tpl_cell : tpl->cells()) { IdString c_name = tpl_cell->name; - bool techmap_replace_cell = (c_name == ID::_TECHMAP_REPLACE_); + bool techmap_replace_cell = c_name.ends_with("_TECHMAP_REPLACE_"); if (techmap_replace_cell) c_name = orig_cell_name; - else if (tpl_cell->name.begins_with("\\_TECHMAP_REPLACE_.")) - c_name = stringf("%s%s", orig_cell_name.c_str(), c_name.c_str() + strlen("\\_TECHMAP_REPLACE_")); + else if (const char *p = strstr(tpl_cell->name.c_str(), "_TECHMAP_REPLACE_.")) + c_name = stringf("%s%s", orig_cell_name.c_str(), p + strlen("_TECHMAP_REPLACE_")); else apply_prefix(cell->name, c_name); @@ -370,13 +364,11 @@ struct TechmapWorker for (auto &it2 : autopurge_ports) c->unsetPort(it2); - if (c->type.in(ID($memrd), ID($memwr), ID($meminit))) { + if (c->has_memid()) { IdString memid = c->getParam(ID::MEMID).decode_string(); log_assert(memory_renames.count(memid) != 0); c->setParam(ID::MEMID, Const(memory_renames[memid].str())); - } - - if (c->type == ID($mem)) { + } else if (c->is_mem_cell()) { IdString memid = c->getParam(ID::MEMID).decode_string(); apply_prefix(cell->name, memid); c->setParam(ID::MEMID, Const(memid.c_str())); @@ -385,10 +377,12 @@ struct TechmapWorker if (c->attributes.count(ID::src)) c->add_strpool_attribute(ID::src, extra_src_attrs); - if (techmap_replace_cell) + if (techmap_replace_cell) { for (auto attr : cell->attributes) if (!c->attributes.count(attr.first)) c->attributes[attr.first] = attr.second; + c->attributes.erase(ID::reprocess_after); + } } for (auto &it : tpl->connections()) { @@ -426,18 +420,7 @@ struct TechmapWorker LogMakeDebugHdl mkdebug; SigMap sigmap(module); - - dict<SigBit, State> init_bits; - pool<SigBit> remove_init_bits; - - for (auto wire : module->wires()) { - if (wire->attributes.count(ID::init)) { - Const value = wire->attributes.at(ID::init); - for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) - if (value[i] != State::Sx) - init_bits[sigmap(SigBit(wire, i))] = value[i]; - } - } + FfInitVals initvals(&sigmap, module); TopoSort<RTLIL::Cell*, IdString::compare_ptr_by_name<RTLIL::Cell>> cells; dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_inbit; @@ -643,6 +626,8 @@ struct TechmapWorker if (tpl->avail_parameters.count(ID::_TECHMAP_CELLTYPE_) != 0) parameters.emplace(ID::_TECHMAP_CELLTYPE_, RTLIL::unescape_id(cell->type)); + if (tpl->avail_parameters.count(ID::_TECHMAP_CELLNAME_) != 0) + parameters.emplace(ID::_TECHMAP_CELLNAME_, RTLIL::unescape_id(cell->name)); for (auto &conn : cell->connections()) { if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))) != 0) { @@ -659,15 +644,7 @@ struct TechmapWorker parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) { - auto sig = sigmap(conn.second); - RTLIL::Const value(State::Sx, sig.size()); - for (int i = 0; i < sig.size(); i++) { - auto it = init_bits.find(sig[i]); - if (it != init_bits.end()) { - value[i] = it->second; - } - } - parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), value); + parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), initvals(conn.second)); } } @@ -748,12 +725,16 @@ struct TechmapWorker for (auto &it : twd) techmap_wire_names.insert(it.first); - for (auto &it : twd[ID::_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(), log_id(it.wire->name), log_signal(value)); - techmap_do_cache[tpl] = false; + for (auto &it : twd) { + if (!it.first.ends_with("_TECHMAP_FAIL_")) + continue; + for (const TechmapWireData &elem : it.second) { + RTLIL::SigSpec value = elem.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(), log_id(elem.wire->name), log_signal(value)); + techmap_do_cache[tpl] = false; + } } } @@ -762,7 +743,7 @@ struct TechmapWorker for (auto &it : twd) { - if (!it.first.begins_with("\\_TECHMAP_DO_") || it.second.empty()) + if (!it.first.contains("_TECHMAP_DO_") || it.second.empty()) continue; auto &data = it.second.front(); @@ -774,7 +755,7 @@ struct TechmapWorker const char *p = data.wire->name.c_str(); const char *q = strrchr(p+1, '.'); - q = q ? q : p+1; + q = q ? q+1 : p+1; std::string cmd_string = data.value.as_const().decode_string(); @@ -817,11 +798,31 @@ struct TechmapWorker } } + // Handle outputs first, as these cannot be remapped. + for (auto &conn : cell->connections()) + { + Wire *twire = tpl->wire(conn.first); + if (!twire->port_output) + continue; + + for (int i = 0; i < GetSize(conn.second); i++) { + RTLIL::SigBit bit = sigmap(conn.second[i]); + RTLIL::SigBit tplbit(twire, i); + cellbits_to_tplbits[bit] = tplbit; + } + } + + // Now handle inputs, remapping as necessary. for (auto &conn : cell->connections()) + { + Wire *twire = tpl->wire(conn.first); + if (twire->port_output) + continue; + for (int i = 0; i < GetSize(conn.second); i++) { RTLIL::SigBit bit = sigmap(conn.second[i]); - RTLIL::SigBit tplbit(tpl->wire(conn.first), i); + RTLIL::SigBit tplbit(twire, i); if (bit.wire == nullptr) { @@ -836,6 +837,7 @@ struct TechmapWorker else cellbits_to_tplbits[bit] = tplbit; } + } RTLIL::SigSig port_conn; for (auto &it : port_connmap) { @@ -870,7 +872,7 @@ struct TechmapWorker TechmapWires twd = techmap_find_special_wires(tpl); for (auto &it : twd) { - if (it.first != ID::_TECHMAP_FAIL_ && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.begins_with("\\_TECHMAP_DO_") && !it.first.begins_with("\\_TECHMAP_DONE_")) + if (!it.first.ends_with("_TECHMAP_FAIL_") && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.contains("_TECHMAP_DO_") && !it.first.contains("_TECHMAP_DONE_")) log_error("Techmap yielded unknown config wire %s.\n", log_id(it.first)); if (techmap_do_cache[tpl]) for (auto &it2 : it.second) @@ -912,7 +914,7 @@ struct TechmapWorker auto sig = sigmap(it->second); for (int i = 0; i < sig.size(); i++) if (val[i] == State::S1) - remove_init_bits.insert(sig[i]); + initvals.remove_init(sig[i]); } } } @@ -961,25 +963,6 @@ struct TechmapWorker handled_cells.insert(cell); } - if (!remove_init_bits.empty()) { - for (auto wire : module->wires()) - if (wire->attributes.count(ID::init)) { - Const &value = wire->attributes.at(ID::init); - bool do_cleanup = true; - for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) { - SigBit bit = sigmap(SigBit(wire, i)); - if (remove_init_bits.count(bit)) - value[i] = State::Sx; - else if (value[i] != State::Sx) - do_cleanup = false; - } - if (do_cleanup) { - log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire)); - wire->attributes.erase(ID::init); - } - } - } - if (log_continue) { log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; @@ -999,7 +982,7 @@ struct TechmapPass : public Pass { log(" techmap [-map filename] [selection]\n"); log("\n"); log("This pass implements a very simple technology mapper that replaces cells in\n"); - log("the design with implementations given in form of a Verilog or ilang source\n"); + log("the design with implementations given in form of a Verilog or RTLIL source\n"); log("file.\n"); log("\n"); log(" -map filename\n"); @@ -1042,7 +1025,9 @@ struct TechmapPass : public Pass { log("\n"); log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n"); log("match cells with a type that match the text value of this attribute. Otherwise\n"); - log("the module name will be used to match the cell.\n"); + log("the module name will be used to match the cell. Multiple space-separated cell\n"); + log("types can be listed, and wildcards using [] will be expanded (ie. \"$_DFF_[PN]_\"\n"); + log("is the same as \"$_DFF_P_ $_DFF_N_\").\n"); log("\n"); 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"); @@ -1111,6 +1096,10 @@ 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_CELLNAME_\n"); + log(" When a parameter with this name exists, it will be set to the 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"); @@ -1220,7 +1209,7 @@ struct TechmapPass : public Pass { if (!map->module(mod->name)) map->add(mod->clone()); } else { - Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend)); + Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend)); } } @@ -1230,8 +1219,27 @@ struct TechmapPass : public Pass { for (auto module : map->modules()) { if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) { char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str()); - for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n")) - celltypeMap[RTLIL::escape_id(q)].insert(module->name); + for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n")) { + std::vector<std::string> queue; + queue.push_back(q); + while (!queue.empty()) { + std::string name = queue.back(); + queue.pop_back(); + auto pos = name.find('['); + if (pos == std::string::npos) { + // No further expansion. + celltypeMap[RTLIL::escape_id(name)].insert(module->name); + } else { + // Expand [] in this name. + auto epos = name.find(']', pos); + if (epos == std::string::npos) + log_error("Malformed techmap_celltype pattern %s\n", q); + for (size_t i = pos + 1; i < epos; i++) { + queue.push_back(name.substr(0, pos) + name[i] + name.substr(epos + 1, std::string::npos)); + } + } + } + } free(p); } else { IdString module_name = module->name.begins_with("\\$") ? @@ -1239,8 +1247,15 @@ struct TechmapPass : public Pass { celltypeMap[module_name].insert(module->name); } } - for (auto &i : celltypeMap) + log_debug("Cell type mappings to use:\n"); + for (auto &i : celltypeMap) { i.second.sort(RTLIL::sort_by_id_str()); + std::string maps = ""; + for (auto &map : i.second) + maps += stringf(" %s", log_id(map)); + log_debug(" %s:%s\n", log_id(i.first), maps.c_str()); + } + log_debug("\n"); for (auto module : design->modules()) worker.module_queue.insert(module); |