From a51df95c47697ea6298c56bccf15c8510584ec3b Mon Sep 17 00:00:00 2001 From: Philippe Sauter Date: Thu, 28 Mar 2024 18:42:16 +0100 Subject: [PATCH 1/2] extract: add arbitrary port width matching - use minimum port width from solver - copy over WIDTH and SIGNED parameters to new cell --- passes/techmap/extract.cc | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc index 137d2217064..2c2f85bfe50 100644 --- a/passes/techmap/extract.cc +++ b/passes/techmap/extract.cc @@ -148,7 +148,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 +206,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; @@ -314,14 +314,25 @@ 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 nsig = sigmap(conn.second); + if (mapping.portMapping.count(conn.first.str()) > 0 && sig2port.has(sigmap(nsig))) { + // copy parameters from haystack to new needle cell + RTLIL::IdString nconn_width = RTLIL::escape_id(conn.first.str() + "_WIDTH"); + RTLIL::IdString nconn_sgn = RTLIL::escape_id(conn.first.str() + "_SIGNED"); + RTLIL::IdString hport_name = mapping.portMapping[conn.first.str()]; + cell->setParam(nconn_width, haystack_cell->getParam(RTLIL::escape_id(hport_name.str() + "_WIDTH"))); + 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"))); + } + // add and connect ports + RTLIL::SigSpec hsig = haystack_cell->getPort(hport_name); + for (int i = 0; i < nsig.size() && i < hsig.size(); i++) + 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); + } } } @@ -427,6 +438,10 @@ 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-sizes between needle port widths and this number\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 +467,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 +572,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 +648,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 +659,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; } From 5c77c73888322872446eaa7ca81fbfd565529d77 Mon Sep 17 00:00:00 2001 From: Philippe Sauter Date: Fri, 14 Jun 2024 10:03:17 +0200 Subject: [PATCH 2/2] extract: trim port widths to minimum This does not yet seem to work completely as intended. The idea is to trim the port widths of the extracted circuits, so that it does not leave X bits as padding at the MSBs. --- passes/techmap/extract.cc | 71 ++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc index 2c2f85bfe50..6535cc8bcae 100644 --- a/passes/techmap/extract.cc +++ b/passes/techmap/extract.cc @@ -103,6 +103,8 @@ class SubCircuitSolver : public SubCircuit::Solver 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) @@ -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)); } } @@ -315,31 +319,59 @@ RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit: for (auto &conn : needle_cell->connections()) { RTLIL::SigSpec nsig = sigmap(conn.second); - if (mapping.portMapping.count(conn.first.str()) > 0 && sig2port.has(sigmap(nsig))) { - // copy parameters from haystack to new needle cell - RTLIL::IdString nconn_width = RTLIL::escape_id(conn.first.str() + "_WIDTH"); - RTLIL::IdString nconn_sgn = RTLIL::escape_id(conn.first.str() + "_SIGNED"); - RTLIL::IdString hport_name = mapping.portMapping[conn.first.str()]; - cell->setParam(nconn_width, haystack_cell->getParam(RTLIL::escape_id(hport_name.str() + "_WIDTH"))); + 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"))); + 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 (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); - + + 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; } @@ -439,7 +471,8 @@ struct ExtractPass : public Pass { log(" don't consider internal signals with more than connections\n"); log("\n"); log(" -min_port_width \n"); - log(" match all subcircuits with port-sizes between needle port widths and this number\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"); @@ -692,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)); }