diff --git a/himbaechel/uarch/gatemate/gatemate.cc b/himbaechel/uarch/gatemate/gatemate.cc index 0b75f649..6b051fc2 100644 --- a/himbaechel/uarch/gatemate/gatemate.cc +++ b/himbaechel/uarch/gatemate/gatemate.cc @@ -425,62 +425,77 @@ void GateMateImpl::preRoute() } } -void GateMateImpl::reassign_bridges(NetInfo *ni, const dict &net_wires, WireId wire, - dict &wire_to_net, int &num) +void GateMateImpl::reassign_bridges(NetInfo *start_net, const dict &net_wires, + WireId start_wire, dict &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 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); } } diff --git a/himbaechel/uarch/gatemate/gatemate.h b/himbaechel/uarch/gatemate/gatemate.h index d2cd8fc9..db954ae4 100644 --- a/himbaechel/uarch/gatemate/gatemate.h +++ b/himbaechel/uarch/gatemate/gatemate.h @@ -131,7 +131,7 @@ struct GateMateImpl : HimbaechelAPI void assign_cell_info(); void route_clock(); void route_mult(); - void reassign_bridges(NetInfo *net, const dict &net_wires, WireId wire, + void reassign_bridges(NetInfo *start_net, const dict &net_wires, WireId start_wire, dict &wire_to_net, int &num); void reassign_cplines(NetInfo *net, const dict &net_wires, WireId wire, dict &wire_to_net, int &num, IdString in_port);