diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc index 137d22170..6535cc8bc 100644 --- a/passes/techmap/extract.cc +++ b/passes/techmap/extract.cc @@ -103,6 +103,8 @@ public: return true; } + // TODO: add an optional check to make sure the port-assignment is in one continous block, not in chunks + if (!ignore_parameters) { std::map needle_param, haystack_param; for (auto &it : needleCell->parameters) @@ -148,7 +150,7 @@ struct bit_ref_t { int bit; }; -bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = nullptr, +bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, int min_port_width = -1, RTLIL::Design *sel = nullptr, int max_fanout = -1, std::set> *split = nullptr) { SigMap sigmap(mod); @@ -206,7 +208,7 @@ bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, for (auto &conn : cell->connections()) { - graph.createPort(cell->name.str(), conn.first.str(), conn.second.size()); + graph.createPort(cell->name.str(), conn.first.str(), conn.second.size(), min_port_width); if (split && split->count(std::pair(cell->type, conn.first)) > 0) continue; @@ -286,7 +288,7 @@ bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, return true; } -RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match) +RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match, bool minimize_port_width=false) { SigMap sigmap(needle); SigSet> sig2port; @@ -296,10 +298,12 @@ RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit: // create cell ports for (auto wire : needle->wires()) { + // for all ports in the needle module if (wire->port_id > 0) { + cell->setPort(wire->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width)); + // remember all bits for (int i = 0; i < wire->width; i++) sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair(wire->name, i)); - cell->setPort(wire->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width)); } } @@ -314,21 +318,60 @@ RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit: continue; for (auto &conn : needle_cell->connections()) { - RTLIL::SigSpec sig = sigmap(conn.second); - if (mapping.portMapping.count(conn.first.str()) > 0 && sig2port.has(sigmap(sig))) { - for (int i = 0; i < sig.size(); i++) - for (auto &port : sig2port.find(sig[i])) { - RTLIL::SigSpec bitsig = haystack_cell->getPort(mapping.portMapping[conn.first.str()]).extract(i, 1); - RTLIL::SigSpec new_sig = cell->getPort(port.first); - new_sig.replace(port.second, bitsig); - cell->setPort(port.first, new_sig); + RTLIL::SigSpec nsig = sigmap(conn.second); + std::string nsig_name = conn.first.str(); + // if it is a mapped port and connects to a wire/port in the needle module + if (mapping.portMapping.count(nsig_name) > 0 && sig2port.has(sigmap(nsig))) { + RTLIL::IdString hport_name = mapping.portMapping[nsig_name]; + + // copy signed-ness from haystack to new needle cell + RTLIL::IdString nconn_sgn = RTLIL::escape_id(nsig_name + "_SIGNED"); + if(haystack_cell->hasParam(RTLIL::escape_id(hport_name.str() + "_SIGNED"))) { + cell->setParam(nconn_sgn, haystack_cell->getParam(RTLIL::escape_id(hport_name.str() + "_SIGNED"))); + } else { + cell->setParam(nconn_sgn, 0); + } + // add and connect ports + RTLIL::SigSpec hsig = haystack_cell->getPort(hport_name); + + for (int i = 0; i < nsig.size() && i < hsig.size(); i++) { // for each bit + // for each needle port connected to wire-bit + for (auto &port : sig2port.find(nsig[i])) { + RTLIL::SigSpec bitsig = hsig.extract(i, 1); + RTLIL::SigSpec new_sig = cell->getPort(port.first); + new_sig.replace(port.second, bitsig); + cell->setPort(port.first, new_sig); + } } } } - haystack->remove(haystack_cell); } + // for all connections/port of the new cell + for (auto &conn : cell->connections()) { + // for all ports in the needle module + RTLIL::IdString port_name = conn.first; + RTLIL::SigSpec port = cell->getPort(conn.first); + if(minimize_port_width) { + // starting from the MSB, remove until first non-constant bit + int msb = port.size()-1; + for (; msb >= 0; msb--) { + if(port[msb].is_wire()) + break; + } + if(msb > 0 && msb < port.size()-1) { + log("removing in %s (width: %d) from bit %d-%d\n", port_name.c_str(), port.size(), port.size()-1, msb+1); + log(" remove(%d, %d)\n", msb+1, port.size()-1-msb); + port.remove(msb+1, port.size()-1-msb); + log("removing in %s (width: %d) from bit %d-%d\n", port_name.c_str(), port.size(), port.size()-1, msb+1); + } + } + + RTLIL::IdString port_width = RTLIL::escape_id(port_name.str() + "_WIDTH"); + cell->setParam(port_width, port.size()); + } + return cell; } @@ -427,6 +470,11 @@ struct ExtractPass : public Pass { log(" -mine_max_fanout \n"); log(" don't consider internal signals with more than connections\n"); log("\n"); + log(" -min_port_width \n"); + log(" match all subcircuits with port widths starting from "); + log(" up to the needle port width defined in the map-design\n"); + log(" default: -1 (exact port width matching)\n"); + log("\n"); log("The modules in the map file may have the attribute 'extract_order' set to an\n"); log("integer value. Then this value is used to determine the order in which the pass\n"); log("tries to map the modules to the design (ascending, default value is 0).\n"); @@ -452,6 +500,7 @@ struct ExtractPass : public Pass { int mine_min_freq = 10; int mine_limit_mod = -1; int mine_max_fanout = -1; + int min_port_width = -1; std::set> mine_split; size_t argidx; @@ -556,6 +605,10 @@ struct ExtractPass : public Pass { argidx += 2; continue; } + if (args[argidx] == "-min_port_width" && argidx+1 < args.size()) { + min_port_width = atoi(args[++argidx].c_str()); + continue; + } break; } extra_args(args, argidx, design); @@ -628,7 +681,7 @@ struct ExtractPass : public Pass { SubCircuit::Graph mod_graph; std::string graph_name = "needle_" + RTLIL::unescape_id(module->name); log("Creating needle graph %s.\n", graph_name.c_str()); - if (module2graph(mod_graph, module, constports)) { + if (module2graph(mod_graph, module, constports, min_port_width)) { solver.addGraph(graph_name, mod_graph); needle_map[graph_name] = module; needle_list.push_back(module); @@ -639,7 +692,7 @@ struct ExtractPass : public Pass { SubCircuit::Graph mod_graph; std::string graph_name = "haystack_" + RTLIL::unescape_id(module->name); log("Creating haystack graph %s.\n", graph_name.c_str()); - if (module2graph(mod_graph, module, constports, design, mine_mode ? mine_max_fanout : -1, mine_mode ? &mine_split : nullptr)) { + if (module2graph(mod_graph, module, constports, -1, design, mine_mode ? mine_max_fanout : -1, mine_mode ? &mine_split : nullptr)) { solver.addGraph(graph_name, mod_graph); haystack_map[graph_name] = module; } @@ -672,7 +725,7 @@ struct ExtractPass : public Pass { log(" %s:%s", it2.first.c_str(), it2.second.c_str()); log("\n"); } - RTLIL::Cell *new_cell = replace(needle_map.at(result.needleGraphId), haystack_map.at(result.haystackGraphId), result); + RTLIL::Cell *new_cell = replace(needle_map.at(result.needleGraphId), haystack_map.at(result.haystackGraphId), result, (min_port_width >= 0)); design->select(haystack_map.at(result.haystackGraphId), new_cell); log(" new cell: %s\n", log_id(new_cell->name)); }