Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

extract: add arbitrary port width matching #4304

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 69 additions & 16 deletions passes/techmap/extract.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<RTLIL::IdString, RTLIL::Const> needle_param, haystack_param;
for (auto &it : needleCell->parameters)
Expand Down Expand Up @@ -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<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = nullptr)
{
SigMap sigmap(mod);
Expand Down Expand Up @@ -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<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0)
continue;
Expand Down Expand Up @@ -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<std::pair<RTLIL::IdString, int>> sig2port;
Expand All @@ -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<RTLIL::IdString, int>(wire->name, i));
cell->setPort(wire->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width));
}
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -427,6 +470,11 @@ struct ExtractPass : public Pass {
log(" -mine_max_fanout <num>\n");
log(" don't consider internal signals with more than <num> connections\n");
log("\n");
log(" -min_port_width <num>\n");
log(" match all subcircuits with port widths starting from <num>");
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");
Expand All @@ -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<std::pair<RTLIL::IdString, RTLIL::IdString>> mine_split;

size_t argidx;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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));
}
Expand Down
Loading