gatemate: removing recursion in GateMateImpl::reassign_bridges (#1697)

* gatemate: removing recursion in GateMateImpl::reassign_bridges

* gatemate: improving comments in GateMateImpl:reassign_bridges

* gatemate: making naming more consistent, adding comments about the need for recursion removal
This commit is contained in:
sylefeb 2026-04-12 09:13:48 +02:00 committed by GitHub
parent a3bccdd33d
commit e6ecd8fab4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 67 additions and 52 deletions

View File

@ -425,62 +425,77 @@ void GateMateImpl::preRoute()
}
}
void GateMateImpl::reassign_bridges(NetInfo *ni, const dict<WireId, PipMap> &net_wires, WireId wire,
dict<WireId, IdString> &wire_to_net, int &num)
void GateMateImpl::reassign_bridges(NetInfo *start_net, const dict<WireId, PipMap> &net_wires,
WireId start_wire, dict<WireId, IdString> &wire_to_net, int &num)
{
wire_to_net.insert({wire, ni->name});
// Processing list, holds parameters to implement the equivalent of recursive calls.
// This avoids a stack overflow when recursion becomes deep, as the function
// has a relatively large stack footprint.
struct record { NetInfo *net; WireId wire; };
std::vector<record> to_process;
// Insert start record.
to_process.push_back({start_net, start_wire});
// For as long as there are pending records, process them.
while (!to_process.empty()) {
// Get the next record to process.
record cur = to_process.back();
to_process.pop_back();
for (auto pip : ctx->getPipsDownhill(wire)) {
auto dst = ctx->getPipDstWire(pip);
wire_to_net.insert({cur.wire, cur.net->name});
// Ignore wires not part of the net
auto it = net_wires.find(dst);
if (it == net_wires.end())
continue;
// Ignore pips if the wire is driven by another pip.
if (pip != it->second.pip)
continue;
// Ignore wires already visited.
if (wire_to_net.count(dst))
continue;
for (auto pip : ctx->getPipsDownhill(cur.wire)) {
auto dst = ctx->getPipDstWire(pip);
const auto &extra_data = *pip_extra_data(pip);
// If not a bridge, just recurse.
if (extra_data.type != PipExtra::PIP_EXTRA_MUX || !(extra_data.flags & MUX_ROUTING)) {
reassign_bridges(ni, net_wires, dst, wire_to_net, num);
continue;
// Ignore wires not part of the net
auto it = net_wires.find(dst);
if (it == net_wires.end())
continue;
// Ignore pips if the wire is driven by another pip.
if (pip != it->second.pip)
continue;
// Ignore wires already visited.
if (wire_to_net.count(dst))
continue;
const auto &extra_data = *pip_extra_data(pip);
// If not a bridge, just recurse.
if (extra_data.type != PipExtra::PIP_EXTRA_MUX || !(extra_data.flags & MUX_ROUTING)) {
// Insert in processing list (recurse).
to_process.push_back({cur.net, dst});
continue;
}
// We have a bridge that needs to be translated to a bel.
IdString name = ctx->idf("%s$bridge%d", cur.net->name.c_str(ctx), num);
IdStringList id = ctx->getPipName(pip);
Loc loc = ctx->getPipLocation(pip);
BelId bel = ctx->getBelByLocation({loc.x, loc.y, CPE_BRIDGE_Z});
CellInfo *cell = ctx->createCell(name, id_CPE_BRIDGE);
ctx->bindBel(bel, cell, PlaceStrength::STRENGTH_FIXED);
cell->params[id_C_BR] = Property(Property::State::S1, 1);
cell->params[id_C_SN] = Property(extra_data.value, 3);
NetInfo *new_net = ctx->createNet(ctx->idf("%s$muxout", name.c_str(ctx)));
IdString in_port = ctx->idf("IN%d", extra_data.value + 1);
auto add_port = [&](const IdString id, PortType dir) {
cell->ports[id].name = id;
cell->ports[id].type = dir;
cell->cell_bel_pins[id] = std::vector{id};
};
add_port(in_port, PORT_IN);
add_port(id_MUXOUT, PORT_OUT);
cell->connectPort(in_port, cur.net);
cell->connectPort(id_MUXOUT, new_net);
pass_backtrace[cell->name][id_MUXOUT] = in_port;
num++;
// Insert in processing list (recurse).
to_process.push_back({new_net, dst});
}
// We have a bridge that needs to be translated to a bel.
IdString name = ctx->idf("%s$bridge%d", ni->name.c_str(ctx), num);
IdStringList id = ctx->getPipName(pip);
Loc loc = ctx->getPipLocation(pip);
BelId bel = ctx->getBelByLocation({loc.x, loc.y, CPE_BRIDGE_Z});
CellInfo *cell = ctx->createCell(name, id_CPE_BRIDGE);
ctx->bindBel(bel, cell, PlaceStrength::STRENGTH_FIXED);
cell->params[id_C_BR] = Property(Property::State::S1, 1);
cell->params[id_C_SN] = Property(extra_data.value, 3);
NetInfo *new_net = ctx->createNet(ctx->idf("%s$muxout", name.c_str(ctx)));
IdString in_port = ctx->idf("IN%d", extra_data.value + 1);
auto add_port = [&](const IdString id, PortType dir) {
cell->ports[id].name = id;
cell->ports[id].type = dir;
cell->cell_bel_pins[id] = std::vector{id};
};
add_port(in_port, PORT_IN);
add_port(id_MUXOUT, PORT_OUT);
cell->connectPort(in_port, ni);
cell->connectPort(id_MUXOUT, new_net);
pass_backtrace[cell->name][id_MUXOUT] = in_port;
num++;
reassign_bridges(new_net, net_wires, dst, wire_to_net, num);
}
}

View File

@ -131,7 +131,7 @@ struct GateMateImpl : HimbaechelAPI
void assign_cell_info();
void route_clock();
void route_mult();
void reassign_bridges(NetInfo *net, const dict<WireId, PipMap> &net_wires, WireId wire,
void reassign_bridges(NetInfo *start_net, const dict<WireId, PipMap> &net_wires, WireId start_wire,
dict<WireId, IdString> &wire_to_net, int &num);
void reassign_cplines(NetInfo *net, const dict<WireId, PipMap> &net_wires, WireId wire,
dict<WireId, IdString> &wire_to_net, int &num, IdString in_port);