diff options
Diffstat (limited to 'passes')
-rw-r--r-- | passes/dfflibmap/Makefile.inc | 6 | ||||
-rw-r--r-- | passes/fsm/fsm_export.cc | 48 | ||||
-rw-r--r-- | passes/hierarchy/hierarchy.cc | 17 | ||||
-rw-r--r-- | passes/opt/opt_const.cc | 6 | ||||
-rw-r--r-- | passes/opt/opt_share.cc | 49 | ||||
-rw-r--r-- | passes/submod/submod.cc | 136 | ||||
-rw-r--r-- | passes/techmap/techmap.cc | 275 |
7 files changed, 396 insertions, 141 deletions
diff --git a/passes/dfflibmap/Makefile.inc b/passes/dfflibmap/Makefile.inc index ed92b299c..b4d73fa12 100644 --- a/passes/dfflibmap/Makefile.inc +++ b/passes/dfflibmap/Makefile.inc @@ -2,9 +2,9 @@ OBJS += passes/dfflibmap/dfflibmap.o OBJS += passes/dfflibmap/libparse.o -TARGETS += filterlib +TARGETS += yosys-filterlib GENFILES += passes/dfflibmap/filterlib.o -filterlib: passes/dfflibmap/filterlib.o - $(CXX) -o filterlib $(LDFLAGS) $^ $(LDLIBS) +yosys-filterlib: passes/dfflibmap/filterlib.o + $(CXX) -o yosys-filterlib $(LDFLAGS) $^ $(LDLIBS) diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc index 26d120a16..dc9ec2b06 100644 --- a/passes/fsm/fsm_export.cc +++ b/passes/fsm/fsm_export.cc @@ -49,7 +49,7 @@ std::string kiss_convert_signal(const RTLIL::SigSpec &sig) { * @param module pointer to module which contains the FSM cell. * @param cell pointer to the FSM cell which should be exported. */ -void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell) { +void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell, std::string filename, bool origenc) { std::map<RTLIL::IdString, RTLIL::Const>::iterator attr_it; FsmData fsm_data; FsmData::transition_t tr; @@ -58,7 +58,9 @@ void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell) { size_t i; attr_it = cell->attributes.find("\\fsm_export"); - if (attr_it != cell->attributes.end() && attr_it->second.str != "") { + if (!filename.empty()) { + kiss_name.assign(filename); + } else if (attr_it != cell->attributes.end() && attr_it->second.str != "") { kiss_name.assign(attr_it->second.str); } else { @@ -84,15 +86,24 @@ void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell) { kiss_file << ".o " << std::dec << fsm_data.num_outputs << std::endl; kiss_file << ".p " << std::dec << fsm_data.transition_table.size() << std::endl; kiss_file << ".s " << std::dec << fsm_data.state_table.size() << std::endl; - kiss_file << ".r s" << std::dec << fsm_data.reset_state << std::endl; + if (origenc) { + kiss_file << ".r " << kiss_convert_signal(fsm_data.state_table[fsm_data.reset_state]) << std::endl; + } else { + kiss_file << ".r s" << std::dec << fsm_data.reset_state << std::endl; + } for (i = 0; i < fsm_data.transition_table.size(); i++) { tr = fsm_data.transition_table[i]; try { kiss_file << kiss_convert_signal(tr.ctrl_in) << ' '; - kiss_file << 's' << tr.state_in << ' '; - kiss_file << 's' << tr.state_out << ' '; + if (origenc) { + kiss_file << kiss_convert_signal(fsm_data.state_table[tr.state_in]) << ' '; + kiss_file << kiss_convert_signal(fsm_data.state_table[tr.state_out]) << ' '; + } else { + kiss_file << 's' << tr.state_in << ' '; + kiss_file << 's' << tr.state_out << ' '; + } kiss_file << kiss_convert_signal(tr.ctrl_out) << std::endl; } catch (int) { @@ -114,21 +125,32 @@ struct FsmExportPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" fsm_export [-noauto] [selection]\n"); + log(" fsm_export [-noauto] [-o filename] [-origenc] [selection]\n"); log("\n"); log("This pass creates a KISS2 file for every selected FSM. For FSMs with the\n"); log("'fsm_export' attribute set, the attribute value is used as filename, otherwise\n"); - log("the module and cell name is used as filename.\n"); + log("the module and cell name is used as filename. If the parameter '-o' is given,\n"); + log("the first exported FSM is written to the specified filename. This overwrites\n"); + log("the setting as specified with the 'fsm_export' attribute. All other FSMs are\n"); + log("exported to the default name as mentioned above.\n"); log("\n"); log(" -noauto\n"); log(" only export FSMs that have the 'fsm_export' attribute set\n"); log("\n"); + log(" -o filename\n"); + log(" filename of the first exported FSM\n"); + log("\n"); + log(" -origenc\n"); + log(" use binary state encoding as state names instead of s0, s1, ...\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { std::map<RTLIL::IdString, RTLIL::Const>::iterator attr_it; std::string arg; bool flag_noauto = false; + std::string filename; + bool flag_origenc = false; size_t argidx; log_header("Executing FSM_EXPORT pass (exporting FSMs in KISS2 file format).\n"); @@ -139,6 +161,15 @@ struct FsmExportPass : public Pass { flag_noauto = true; continue; } + if (arg == "-o") { + argidx++; + filename = args[argidx]; + continue; + } + if (arg == "-origenc") { + flag_origenc = true; + continue; + } break; } extra_args(args, argidx, design); @@ -149,7 +180,8 @@ struct FsmExportPass : public Pass { if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second)) { attr_it = cell_it.second->attributes.find("\\fsm_export"); if (!flag_noauto || (attr_it != cell_it.second->attributes.end())) { - write_kiss2(mod_it.second, cell_it.second); + write_kiss2(mod_it.second, cell_it.second, filename, flag_origenc); + filename.clear(); } } } diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 04274990d..287f93097 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -50,17 +50,21 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell for (auto &celltype : found_celltypes) { std::set<std::string> portnames; + std::set<std::string> parameters; std::map<std::string, int> portwidths; log("Generate module for cell type %s:\n", celltype.c_str()); for (auto i1 : design->modules) for (auto i2 : i1.second->cells) - if (i2.second->type == celltype) + if (i2.second->type == celltype) { for (auto &conn : i2.second->connections) { if (conn.first[0] != '$') portnames.insert(conn.first); portwidths[conn.first] = std::max(portwidths[conn.first], conn.second.width); } + for (auto ¶ : i2.second->parameters) + parameters.insert(para.first); + } for (auto &decl : portdecls) if (decl.index > 0) @@ -109,6 +113,7 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell RTLIL::Module *mod = new RTLIL::Module; mod->name = celltype; + mod->attributes["\\placeholder"] = RTLIL::Const(0, 0); design->modules[mod->name] = mod; for (auto &decl : ports) { @@ -121,6 +126,9 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell mod->add(wire); } + for (auto ¶ : parameters) + log(" ignoring parameter %s.\n", RTLIL::id2cstr(para)); + log(" module %s created.\n", RTLIL::id2cstr(mod->name)); } } @@ -139,9 +147,12 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla } if (cell->parameters.size() == 0) continue; + if (design->modules.at(cell->type)->attributes.count("\\placeholder") > 0) + continue; RTLIL::Module *mod = design->modules[cell->type]; cell->type = mod->derive(design, cell->parameters); cell->parameters.clear(); + did_something = true; } if (did_something) @@ -200,7 +211,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla if (auto_sizes.size() > 0) { module->update_auto_wires(auto_sizes); - log_header("Continuing EXPAND pass.\n"); + log_header("Continuing HIERARCHY pass.\n"); did_something = true; } @@ -262,7 +273,7 @@ struct HierarchyPass : public Pass { log(" use the specified top module to built a design hierarchy. modules\n"); log(" outside this tree (unused modules) are removed.\n"); log("\n"); - log("In -generate mode this pass generates skeletton modules for the given cell\n"); + log("In -generate mode this pass generates placeholder modules for the given cell\n"); log("types (wildcards supported). For this the design is searched for cells that\n"); log("match the given types and then the given port declarations are used to\n"); log("determine the direction of the ports. The syntax for a port declaration is:\n"); diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_const.cc index 0effd964b..7c82f0fcb 100644 --- a/passes/opt/opt_const.cc +++ b/passes/opt/opt_const.cc @@ -181,8 +181,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module) RTLIL::SigSpec b = assign_map(cell->connections["\\B"]); if (a.is_fully_const()) { - RTLIL::SigSpec tmp = a; - a = b, b = tmp; + RTLIL::SigSpec tmp; + tmp = a, a = b, b = tmp; + cell->connections["\\A"] = a; + cell->connections["\\B"] = b; } if (b.is_fully_const()) { diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc index 9f79d0603..43d1a57e1 100644 --- a/passes/opt/opt_share.cc +++ b/passes/opt/opt_share.cc @@ -65,7 +65,32 @@ struct OptShareWorker for (auto &it : cell->parameters) hash_string += "P " + it.first + "=" + it.second.as_string() + "\n"; - for (auto &it : cell->connections) { + const std::map<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections; + std::map<RTLIL::IdString, RTLIL::SigSpec> alt_conn; + + if (cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" || cell->type == "$add" || cell->type == "$mul" || + cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_") { + alt_conn = *conn; + if (assign_map(alt_conn.at("\\A")) < assign_map(alt_conn.at("\\B"))) { + alt_conn["\\A"] = conn->at("\\B"); + alt_conn["\\B"] = conn->at("\\A"); + } + conn = &alt_conn; + } else + if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor") { + alt_conn = *conn; + assign_map.apply(alt_conn.at("\\A")); + alt_conn.at("\\A").sort(); + conn = &alt_conn; + } else + if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_bool") { + alt_conn = *conn; + assign_map.apply(alt_conn.at("\\A")); + alt_conn.at("\\A").sort_and_unify(); + conn = &alt_conn; + } + + for (auto &it : *conn) { if (ct.cell_output(cell->type, it.first)) continue; RTLIL::SigSpec sig = it.second; @@ -126,6 +151,28 @@ struct OptShareWorker assign_map.apply(it.second); } + if (cell1->type == "$and" || cell1->type == "$or" || cell1->type == "$xor" || cell1->type == "$xnor" || cell1->type == "$add" || cell1->type == "$mul" || + cell1->type == "$logic_and" || cell1->type == "$logic_or" || cell1->type == "$_AND_" || cell1->type == "$_OR_" || cell1->type == "$_XOR_") { + if (conn1.at("\\A") < conn1.at("\\B")) { + RTLIL::SigSpec tmp = conn1["\\A"]; + conn1["\\A"] = conn1["\\B"]; + conn1["\\B"] = tmp; + } + if (conn2.at("\\A") < conn2.at("\\B")) { + RTLIL::SigSpec tmp = conn2["\\A"]; + conn2["\\A"] = conn2["\\B"]; + conn2["\\B"] = tmp; + } + } else + if (cell1->type == "$reduce_xor" || cell1->type == "$reduce_xnor") { + conn1["\\A"].sort(); + conn2["\\A"].sort(); + } else + if (cell1->type == "$reduce_and" || cell1->type == "$reduce_or" || cell1->type == "$reduce_bool") { + conn1["\\A"].sort_and_unify(); + conn2["\\A"].sort_and_unify(); + } + if (conn1 != conn2) { lt = conn1 < conn2; return true; diff --git a/passes/submod/submod.cc b/passes/submod/submod.cc index f91d1ec3a..98854da23 100644 --- a/passes/submod/submod.cc +++ b/passes/submod/submod.cc @@ -29,6 +29,7 @@ struct SubmodWorker CellTypes ct; RTLIL::Design *design; RTLIL::Module *module; + std::string opt_name; struct SubModule { @@ -188,9 +189,9 @@ struct SubmodWorker module->cells[new_cell->name] = new_cell; } - SubmodWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module) + SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, std::string opt_name = std::string()) : design(design), module(module), opt_name(opt_name) { - if (!design->selected_whole_module(module->name)) + if (!design->selected_whole_module(module->name) && opt_name.empty()) return; if (module->processes.size() > 0) { @@ -208,29 +209,47 @@ struct SubmodWorker ct.setup_stdcells(); ct.setup_stdcells_mem(); - for (auto &it : module->wires) - it.second->attributes.erase("\\submod"); - - for (auto &it : module->cells) + if (opt_name.empty()) { - RTLIL::Cell *cell = it.second; - if (cell->attributes.count("\\submod") == 0 || cell->attributes["\\submod"].str.size() == 0) { + for (auto &it : module->wires) + it.second->attributes.erase("\\submod"); + + for (auto &it : module->cells) + { + RTLIL::Cell *cell = it.second; + if (cell->attributes.count("\\submod") == 0 || cell->attributes["\\submod"].str.size() == 0) { + cell->attributes.erase("\\submod"); + continue; + } + + std::string submod_str = cell->attributes["\\submod"].str; cell->attributes.erase("\\submod"); - continue; - } - std::string submod_str = cell->attributes["\\submod"].str; - cell->attributes.erase("\\submod"); + if (submodules.count(submod_str) == 0) { + submodules[submod_str].name = submod_str; + submodules[submod_str].full_name = module->name + "_" + submod_str; + while (design->modules.count(submodules[submod_str].full_name) != 0 || + module->count_id(submodules[submod_str].full_name) != 0) + submodules[submod_str].full_name += "_"; + } - if (submodules.count(submod_str) == 0) { - submodules[submod_str].name = submod_str; - submodules[submod_str].full_name = module->name + "_" + submod_str; - while (design->modules.count(submodules[submod_str].full_name) != 0 || - module->count_id(submodules[submod_str].full_name) != 0) - submodules[submod_str].full_name += "_"; + submodules[submod_str].cells.insert(cell); + } + } + else + { + for (auto &it : module->cells) + { + RTLIL::Cell *cell = it.second; + if (!design->selected(module, cell)) + continue; + submodules[opt_name].name = opt_name; + submodules[opt_name].full_name = RTLIL::escape_id(opt_name); + submodules[opt_name].cells.insert(cell); } - submodules[submod_str].cells.insert(cell); + if (submodules.size() == 0) + log("Nothing selected -> do nothing.\n"); } for (auto &it : submodules) @@ -256,35 +275,72 @@ struct SubmodPass : public Pass { log("This pass only operates on completely selected modules with no processes\n"); log("or memories.\n"); log("\n"); + log("\n"); + log(" submod -name <name> [selection]\n"); + log("\n"); + log("As above, but don't use the 'submod' attribute but instead use the selection.\n"); + log("Only objects from one module might be selected. The value of the -name option\n"); + log("is used as the value of the 'submod' attribute above.\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { log_header("Executing SUBMOD pass (moving cells to submodules as requested).\n"); log_push(); - Pass::call(design, "opt_rmunused"); - log_header("Continuing SUBMOD pass.\n"); - - extra_args(args, 1, design); - - std::set<std::string> handled_modules; - - bool did_something = true; - while (did_something) { - did_something = false; - std::vector<std::string> queued_modules; - for (auto &mod_it : design->modules) - if (handled_modules.count(mod_it.first) == 0) - queued_modules.push_back(mod_it.first); - for (auto &modname : queued_modules) - if (design->modules.count(modname) != 0) { - SubmodWorker worker(design, design->modules[modname]); - handled_modules.insert(modname); - did_something = true; - } + std::string opt_name; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-name" && argidx+1 < args.size()) { + opt_name = args[++argidx]; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (opt_name.empty()) + { + Pass::call(design, "opt_rmunused"); + log_header("Continuing SUBMOD pass.\n"); + + std::set<std::string> handled_modules; + + bool did_something = true; + while (did_something) { + did_something = false; + std::vector<std::string> queued_modules; + for (auto &mod_it : design->modules) + if (handled_modules.count(mod_it.first) == 0 && design->selected_whole_module(mod_it.first)) + queued_modules.push_back(mod_it.first); + for (auto &modname : queued_modules) + if (design->modules.count(modname) != 0) { + SubmodWorker worker(design, design->modules[modname]); + handled_modules.insert(modname); + did_something = true; + } + } + + Pass::call(design, "opt_rmunused"); + } + else + { + RTLIL::Module *module = NULL; + for (auto &mod_it : design->modules) { + if (!design->selected_module(mod_it.first)) + continue; + if (module != NULL) + log_cmd_error("More than one module selected: %s %s\n", module->name.c_str(), mod_it.first.c_str()); + module = mod_it.second; + } + if (module == NULL) + log("Nothing selected -> do nothing.\n"); + else + SubmodWorker worker(design, module, opt_name); } - Pass::call(design, "opt_rmunused"); + log_pop(); } } SubmodPass; diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 5fd5858aa..732bd5cb9 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -31,7 +31,7 @@ static void apply_prefix(std::string prefix, std::string &id) if (id[0] == '\\') id = prefix + "." + id.substr(1); else - id = prefix + "." + id; + id = "$techmap" + prefix + "." + id; } static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) @@ -47,8 +47,93 @@ static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module } std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache; +std::map<RTLIL::Module*, bool> techmap_fail_cache; -static bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map) +static bool techmap_fail_check(RTLIL::Module *module) +{ + if (module == NULL) + return false; + + if (techmap_fail_cache.count(module) > 0) + return techmap_fail_cache.at(module); + + for (auto &it : module->wires) { + std::string name = it.first; + if (name == "\\TECHMAP_FAIL") + return techmap_fail_cache[module] = true; + if (name.size() > 13 && name[0] == '\\' && name.substr(name.size()-13) == ".TECHMAP_FAIL") + return techmap_fail_cache[module] = true; + } + + return techmap_fail_cache[module] = false; +} + +static void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl) +{ + 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."); + + if (tpl->processes.size() != 0) + log_error("Technology map yielded processes -> this is not supported."); + + for (auto &it : tpl->wires) { + 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; + module->wires[w->name] = w; + design->select(module, w); + } + + for (auto &it : tpl->cells) { + RTLIL::Cell *c = new RTLIL::Cell(*it.second); + if (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); + 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); + module->connections.push_back(c); + } + + for (auto &it : cell->connections) { + if (tpl->wires.count(it.first) == 0 || tpl->wires.at(it.first)->port_id == 0) + continue; + RTLIL::Wire *w = tpl->wires[it.first]; + 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); + module->connections.push_back(c); + } + + module->cells.erase(cell->name); + delete cell; +} + +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) { if (!design->selected(module)) return false; @@ -67,98 +152,55 @@ static bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL:: RTLIL::Cell *cell = module->cells[cell_name]; - if (!design->selected(module, cell)) + if (!design->selected(module, cell) || handled_cells.count(cell) > 0) continue; - if (map->modules.count(cell->type) == 0) + if (celltypeMap.count(cell->type) == 0) continue; - RTLIL::Module *tpl = map->modules[cell->type]; - std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(cell->type, cell->parameters); - - if (techmap_cache.count(key) > 0) { - tpl = techmap_cache[key]; - } else { - std::string derived_name = cell->type; - if (cell->parameters.size() != 0) { - derived_name = tpl->derive(map, cell->parameters); - tpl = map->modules[derived_name]; - log_header("Continuing TECHMAP pass.\n"); + for (auto &tpl_name : celltypeMap.at(cell->type)) + { + std::string derived_name = tpl_name; + RTLIL::Module *tpl = map->modules[tpl_name]; + std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters; + + for (auto conn : cell->connections) { + 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) + goto next_tpl; + parameters[conn.first] = conn.second.as_const(); } - for (auto &cit : tpl->cells) - if (cit.second->type == "\\TECHMAP_FAILED") { - log("Not using module `%s' from techmap as it contains a TECHMAP_FAILED marker cell.\n", derived_name.c_str()); - tpl = NULL; - break; - } - techmap_cache[key] = tpl; - } - - if (tpl == NULL) - goto next_cell; - - log("Mapping `%s.%s' using `%s'.\n", module->name.c_str(), cell_name.c_str(), tpl->name.c_str()); - - if (tpl->memories.size() != 0) - log_error("Technology map yielded memories -> this is not supported."); - if (tpl->processes.size() != 0) - log_error("Technology map yielded processes -> this is not supported."); - - for (auto &it : tpl->wires) { - 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; - module->wires[w->name] = w; - design->select(module, w); - } - - for (auto &it : tpl->cells) { - RTLIL::Cell *c = new RTLIL::Cell(*it.second); - if (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); - 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); - module->connections.push_back(c); - } + if (0) { + next_tpl: + continue; + } - for (auto &it : cell->connections) { - assert(tpl->wires.count(it.first)); - assert(tpl->wires[it.first]->port_id > 0); - RTLIL::Wire *w = tpl->wires[it.first]; - RTLIL::SigSig c; - if (w->port_output) { - c.first = it.second; - c.second = RTLIL::SigSpec(w); - apply_prefix(cell_name, c.second, module); + 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 { - c.first = RTLIL::SigSpec(w); - c.second = it.second; - apply_prefix(cell_name, c.first, module); + if (cell->parameters.size() != 0) { + derived_name = tpl->derive(map, parameters); + tpl = map->modules[derived_name]; + log_header("Continuing TECHMAP pass.\n"); + } + techmap_cache[key] = tpl; } - 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); - module->connections.push_back(c); + + if (techmap_fail_check(tpl)) { + log("Not using module `%s' from techmap as it contains a TECHMAP_FAIL marker wire.\n", derived_name.c_str()); + continue; + } + + techmap_module_worker(design, module, cell, tpl); + did_something = true; + cell = NULL; + break; } - delete cell; - module->cells.erase(cell_name); - did_something = true; - next_cell:; + handled_cells.insert(cell); } return did_something; @@ -182,8 +224,23 @@ struct TechmapPass : public Pass { log(" transforms the internal RTL cells to the internal gate\n"); log(" library.\n"); log("\n"); + log("When a module in the map file has the 'celltype' attribute set, it will match\n"); + log("cells with a type that match the text value of this attribute.\n"); + log("\n"); + log("When a module in the map file contains a wire with the name 'TECHMAP_FAIL' (or\n"); + log("one matching '*.TECHMAP_FAIL') then no substitution will be performed. The\n"); + log("modules in the map file are tried in alphabetical order.\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("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"); + log("esentially techmap but using the design itself as map library).\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { @@ -220,18 +277,68 @@ struct TechmapPass : public Pass { } map->modules.swap(modules_new); + std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap; + for (auto &it : map->modules) { + if (it.second->attributes.count("\\celltype") && !it.second->attributes.at("\\celltype").str.empty()) { + celltypeMap[RTLIL::escape_id(it.second->attributes.at("\\celltype").str)].insert(it.first); + } else + 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)) + if (techmap_module(design, mod_it.second, map, handled_cells, celltypeMap)) did_something = true; } log("No more expansions possible.\n"); techmap_cache.clear(); + techmap_fail_cache.clear(); delete map; log_pop(); } } TechmapPass; +struct FlattenPass : public Pass { + FlattenPass() : Pass("flatten", "flatten design") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" flatten [selection]\n"); + log("\n"); + log("This pass flattens the design by replacing cells by their implementation. This\n"); + log("pass is very simmilar to the 'techmap' pass. The only difference is that this\n"); + log("pass is using the current design as mapping library.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + log_header("Executing FLATTEN pass (flatten design).\n"); + log_push(); + + extra_args(args, 1, design); + + std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap; + for (auto &it : design->modules) + 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, design, handled_cells, celltypeMap)) + did_something = true; + } + + log("No more expansions possible.\n"); + techmap_cache.clear(); + techmap_fail_cache.clear(); + log_pop(); + } +} FlattenPass; + |