diff options
| author | Clifford Wolf <clifford@clifford.at> | 2018-11-09 17:00:45 +0100 | 
|---|---|---|
| committer | Clifford Wolf <clifford@clifford.at> | 2018-11-09 17:00:45 +0100 | 
| commit | aeaa0552ba0373fb1edaed263b6edb4e8e82d7ea (patch) | |
| tree | dc436d4ae006f6bfe7bb78c78b46ece3a53a6751 /common | |
| parent | 66dd17664c08aca17b53d2853558121aa9e702e4 (diff) | |
| download | nextpnr-aeaa0552ba0373fb1edaed263b6edb4e8e82d7ea.tar.gz nextpnr-aeaa0552ba0373fb1edaed263b6edb4e8e82d7ea.tar.bz2 nextpnr-aeaa0552ba0373fb1edaed263b6edb4e8e82d7ea.zip | |
Essentially a rewrite router1
Signed-off-by: Clifford Wolf <clifford@clifford.at>
Diffstat (limited to 'common')
| -rw-r--r-- | common/router1.cc | 1118 | ||||
| -rw-r--r-- | common/router1.h | 5 | 
2 files changed, 341 insertions, 782 deletions
| diff --git a/common/router1.cc b/common/router1.cc index 34554711..c4d4a130 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -28,24 +28,38 @@ namespace {  USING_NEXTPNR_NAMESPACE -struct hash_id_wire +struct arc_key  { -    std::size_t operator()(const std::pair<IdString, WireId> &arg) const noexcept -    { -        std::size_t seed = std::hash<IdString>()(arg.first); -        seed ^= std::hash<WireId>()(arg.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); -        return seed; +    NetInfo *net_info; +    int user_idx; + +    bool operator==(const arc_key &other) const { +        return (net_info == other.net_info) && (user_idx == other.user_idx);      } + +    struct Hash +    { +        std::size_t operator()(const arc_key &arg) const noexcept +        { +            std::size_t seed = std::hash<NetInfo*>()(arg.net_info); +            seed ^= std::hash<int>()(arg.user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +            return seed; +        } +    };  }; -struct hash_id_pip +struct arc_entry  { -    std::size_t operator()(const std::pair<IdString, PipId> &arg) const noexcept +    arc_key arc; +    delay_t pri; + +    struct Greater      { -        std::size_t seed = std::hash<IdString>()(arg.first); -        seed ^= std::hash<PipId>()(arg.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); -        return seed; -    } +        bool operator()(const arc_entry &lhs, const arc_entry &rhs) const noexcept +        { +            return lhs.pri > rhs.pri; +        } +    };  };  struct QueuedWire @@ -67,631 +81,388 @@ struct QueuedWire      };  }; -struct RipupScoreboard -{ -    std::unordered_map<WireId, int> wireScores; -    std::unordered_map<PipId, int> pipScores; -    std::unordered_map<std::pair<IdString, WireId>, int, hash_id_wire> netWireScores; -    std::unordered_map<std::pair<IdString, PipId>, int, hash_id_pip> netPipScores; -}; - -void ripup_net(Context *ctx, IdString net_name) -{ -    if (ctx->debug) -        log("Ripping up all routing for net %s.\n", net_name.c_str(ctx)); - -    auto net_info = ctx->nets.at(net_name).get(); -    std::vector<PipId> pips; -    std::vector<WireId> wires; - -    pips.reserve(net_info->wires.size()); -    wires.reserve(net_info->wires.size()); - -    for (auto &it : net_info->wires) { -        if (it.second.pip != PipId()) -            pips.push_back(it.second.pip); -        else -            wires.push_back(it.first); -    } - -    for (auto pip : pips) -        ctx->unbindPip(pip); - -    for (auto wire : wires) -        ctx->unbindWire(wire); - -    NPNR_ASSERT(net_info->wires.empty()); -} - -struct Router +struct Router1  {      Context *ctx;      const Router1Cfg &cfg; -    RipupScoreboard scores; -    IdString net_name; -    bool ripup; -    delay_t ripup_penalty; +    std::priority_queue<arc_entry, std::vector<arc_entry>, arc_entry::Greater> arc_queue; +    std::unordered_map<WireId, std::unordered_set<arc_key, arc_key::Hash>> wire_to_arc; +    std::unordered_set<arc_key, arc_key::Hash> queued_arcs; -    std::unordered_set<IdString> rippedNets;      std::unordered_map<WireId, QueuedWire> visited; -    int visitCnt = 0, revisitCnt = 0, overtimeRevisitCnt = 0; -    bool routedOkay = false; -    delay_t maxDelay = 0.0; -    WireId failedDest; - -    void route(const std::unordered_map<WireId, delay_t> &src_wires, WireId dst_wire, delay_t max_delay) -    { -        std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue; - -        visited.clear(); - -        for (auto &it : src_wires) { -            QueuedWire qw; -            qw.wire = it.first; -            qw.pip = PipId(); -            qw.delay = it.second; -            qw.penalty = -(it.second / 16); -            if (cfg.useEstimate) -                qw.togo = ctx->estimateDelay(qw.wire, dst_wire); -            qw.randtag = ctx->rng(); - -            queue.push(qw); -            visited[qw.wire] = qw; -        } - -        int thisVisitCnt = 0; -        int thisVisitCntLimit = 0; - -        while (!queue.empty() && (thisVisitCntLimit == 0 || thisVisitCnt < thisVisitCntLimit)) { -            QueuedWire qw = queue.top(); -            queue.pop(); +    std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue; -            if (thisVisitCntLimit == 0 && visited.count(dst_wire)) -                thisVisitCntLimit = (thisVisitCnt * 3) / 2; - -            for (auto pip : ctx->getPipsDownhill(qw.wire)) { -                delay_t next_delay = qw.delay + ctx->getPipDelay(pip).maxDelay(); -                delay_t next_penalty = qw.penalty; -                WireId next_wire = ctx->getPipDstWire(pip); -                bool foundRipupNet = false; -                thisVisitCnt++; - -                next_delay += ctx->getWireDelay(next_wire).maxDelay(); - -                if (max_delay > 0 && next_delay > max_delay) -                    continue; - -                if (!ctx->checkWireAvail(next_wire)) { -                    if (!ripup) -                        continue; -                    NetInfo *ripupWireNet = ctx->getConflictingWireNet(next_wire); -                    if (ripupWireNet == nullptr || ripupWireNet->name == net_name) -                        continue; - -                    auto it1 = scores.wireScores.find(next_wire); -                    if (it1 != scores.wireScores.end()) -                        next_penalty += (it1->second * ripup_penalty) / 8; +    std::unordered_map<WireId, int> wireScores; +    std::unordered_map<PipId, int> pipScores; -                    auto it2 = scores.netWireScores.find(std::make_pair(ripupWireNet->name, next_wire)); -                    if (it2 != scores.netWireScores.end()) -                        next_penalty += it2->second * ripup_penalty; +    int arcs_with_ripup = 0; +    int arcs_without_ripup = 0; +    bool ripup_flag; -                    foundRipupNet = true; -                } +    Router1(Context *ctx, const Router1Cfg &cfg) : ctx(ctx), cfg(cfg) { } -                if (!ctx->checkPipAvail(pip)) { -                    if (!ripup) -                        continue; -                    NetInfo *ripupPipNet = ctx->getConflictingPipNet(pip); -                    if (ripupPipNet == nullptr || ripupPipNet->name == net_name) -                        continue; +    void arc_queue_insert(const arc_key &arc, WireId src_wire, WireId dst_wire) +    { +        if (queued_arcs.count(arc)) +            return; -                    auto it1 = scores.pipScores.find(pip); -                    if (it1 != scores.pipScores.end()) -                        next_penalty += (it1->second * ripup_penalty) / 8; +        delay_t pri = ctx->estimateDelay(src_wire, dst_wire) - arc.net_info->users[arc.user_idx].budget; -                    auto it2 = scores.netPipScores.find(std::make_pair(ripupPipNet->name, pip)); -                    if (it2 != scores.netPipScores.end()) -                        next_penalty += it2->second * ripup_penalty; +        arc_entry entry; +        entry.arc = arc; +        entry.pri = pri; -                    foundRipupNet = true; -                } - -                if (foundRipupNet) -                    next_penalty += ripup_penalty; +        arc_queue.push(entry); +        queued_arcs.insert(arc); +    } -                NPNR_ASSERT(next_delay >= 0); -                NPNR_ASSERT(next_delay + next_penalty >= 0); +    void arc_queue_insert(const arc_key &arc) +    { +        NetInfo *net_info = arc.net_info; +        int user_idx = arc.user_idx; -                if (visited.count(next_wire)) { -                    if (visited.at(next_wire).delay + visited.at(next_wire).penalty <= next_delay + next_penalty + ctx->getDelayEpsilon()) -                        continue; -#if 0 // FIXME -                    if (ctx->debug) -                        log("Found better route to %s. Old vs new delay estimate: %.3f %.3f\n", -                            ctx->getWireName(next_wire).c_str(), -                            ctx->getDelayNS(visited.at(next_wire).delay), -                            ctx->getDelayNS(next_delay)); -#endif -                    if (thisVisitCntLimit == 0) -                        revisitCnt++; -                    else -                        overtimeRevisitCnt++; -                } +        auto src_wire = ctx->getNetinfoSourceWire(net_info); +        auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); -                QueuedWire next_qw; -                next_qw.wire = next_wire; -                next_qw.pip = pip; -                next_qw.delay = next_delay; -                next_qw.penalty = next_penalty; -                if (cfg.useEstimate) -                    next_qw.togo = ctx->estimateDelay(next_wire, dst_wire); -                next_qw.randtag = ctx->rng(); +        arc_queue_insert(arc, src_wire, dst_wire); +    } -                visited[next_qw.wire] = next_qw; -                queue.push(next_qw); -            } +    void ripup_net(NetInfo *net) +    { +        if (ctx->debug) +            log("    ripup net %s\n", net->name.c_str(ctx)); + +        auto net_wires_copy = net->wires; +        for (auto &it : net_wires_copy) { +            if (it.second.pip == PipId()) +                ripup_wire(it.first); +            else +                ripup_pip(it.second.pip);          } -        visitCnt += thisVisitCnt; +        ripup_flag = true;      } -    Router(Context *ctx, const Router1Cfg &cfg, RipupScoreboard &scores, WireId src_wire, WireId dst_wire, -           bool ripup = false, delay_t ripup_penalty = 0) -            : ctx(ctx), cfg(cfg), scores(scores), ripup(ripup), ripup_penalty(ripup_penalty) +    void ripup_wire(WireId wire)      { -        std::unordered_map<WireId, delay_t> src_wires; -        src_wires[src_wire] = ctx->getWireDelay(src_wire).maxDelay(); -        route(src_wires, dst_wire, 0); -        routedOkay = visited.count(dst_wire); - -        if (ctx->debug) { -            log("Route (from destination to source):\n"); - -            WireId cursor = dst_wire; +        if (ctx->debug) +            log("    ripup wire %s\n", ctx->getWireName(wire).c_str(ctx)); -            while (1) { -                log("  %8.3f %s\n", ctx->getDelayNS(visited[cursor].delay), ctx->getWireName(cursor).c_str(ctx)); +        wireScores[wire]++; -                if (cursor == src_wire) -                    break; +        if (ctx->getBoundWireNet(wire)) { +            for (auto &it : wire_to_arc[wire]) +                arc_queue_insert(it); +            wire_to_arc[wire].clear(); +            ctx->unbindWire(wire); +        } -                cursor = ctx->getPipSrcWire(visited[cursor].pip); -            } +        NetInfo *net = ctx->getConflictingWireNet(wire); +        if (net != nullptr) { +            wireScores[wire] += net->wires.size(); +            ripup_net(net);          } + +        ripup_flag = true;      } -    Router(Context *ctx, const Router1Cfg &cfg, RipupScoreboard &scores, IdString net_name, int user_idx = -1, -           bool reroute = false, bool ripup = false, delay_t ripup_penalty = 0) -            : ctx(ctx), cfg(cfg), scores(scores), net_name(net_name), ripup(ripup), ripup_penalty(ripup_penalty) +    void ripup_pip(PipId pip)      { -        auto net_info = ctx->nets.at(net_name).get(); -          if (ctx->debug) -            log("Routing net %s.\n", net_name.c_str(ctx)); +            log("    ripup pip %s\n", ctx->getPipName(pip).c_str(ctx)); -        if (ctx->debug) -            log("  Source: %s.%s.\n", net_info->driver.cell->name.c_str(ctx), net_info->driver.port.c_str(ctx)); +        WireId wire = ctx->getPipDstWire(pip); +        wireScores[wire]++; +        pipScores[pip]++; -        auto src_wire = ctx->getNetinfoSourceWire(net_info); +        if (ctx->getBoundPipNet(pip)) { +            for (auto &it : wire_to_arc[wire]) +                arc_queue_insert(it); +            wire_to_arc[wire].clear(); +            ctx->unbindPip(pip); +        } -        if (src_wire == WireId()) -            log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx), -                      net_info->driver.cell->name.c_str(ctx)); +        NetInfo *net = ctx->getConflictingPipNet(pip); +        if (net != nullptr) { +            wireScores[wire] += net->wires.size(); +            pipScores[pip] += net->wires.size(); +            ripup_net(net); +        } -        if (ctx->debug) -            log("    Source wire: %s\n", ctx->getWireName(src_wire).c_str(ctx)); +        ripup_flag = true; +    } -        std::unordered_map<WireId, delay_t> src_wires; -        std::vector<std::pair<delay_t, int>> users_array; +    void setup() +    { +        for (auto &net_it : ctx->nets) +        { +            NetInfo *net_info = net_it.second.get(); -        if (user_idx < 0) { -            // route all users, from worst to best slack -            for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { -                auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); -                delay_t slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); -                users_array.push_back(std::pair<delay_t, int>(slack, user_idx)); -            } -            std::sort(users_array.begin(), users_array.end()); -        } else { -            // route only the selected user -            users_array.push_back(std::pair<delay_t, int>(delay_t(), user_idx)); -        } +#ifdef ARCH_ECP5 +            // ECP5 global nets currently appear part-unrouted due to arch database limitations +            // Don't touch them in the router +            if (net_info->is_global) +                return; +#endif +            if (net_info->driver.cell == nullptr) +                return; -        if (reroute) { -            // complete ripup -            ripup_net(ctx, net_name); -            ctx->bindWire(src_wire, ctx->nets.at(net_name).get(), STRENGTH_WEAK); -            src_wires[src_wire] = ctx->getWireDelay(src_wire).maxDelay(); -        } else { -            // re-use existing routes as much as possible -            if (net_info->wires.count(src_wire) == 0) -                ctx->bindWire(src_wire, ctx->nets.at(net_name).get(), STRENGTH_WEAK); -            src_wires[src_wire] = ctx->getWireDelay(src_wire).maxDelay(); +            auto src_wire = ctx->getNetinfoSourceWire(net_info); + +            if (src_wire == WireId()) +                log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx), +                          net_info->driver.cell->name.c_str(ctx));              for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {                  auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]);                  if (dst_wire == WireId()) -                    log_error("No wire found for port %s on destination cell %s.\n", -                              net_info->users[user_idx].port.c_str(ctx), +                    log_error("No wire found for port %s on destination cell %s.\n", net_info->users[user_idx].port.c_str(ctx),                                net_info->users[user_idx].cell->name.c_str(ctx)); -                std::function<delay_t(WireId)> register_existing_path = -                        [ctx, net_info, &src_wires, ®ister_existing_path](WireId wire) -> delay_t { -                    auto it = src_wires.find(wire); -                    if (it != src_wires.end()) -                        return it->second; - -                    PipId pip = net_info->wires.at(wire).pip; -                    delay_t delay = register_existing_path(ctx->getPipSrcWire(pip)); -                    delay += ctx->getPipDelay(pip).maxDelay(); -                    delay += ctx->getWireDelay(wire).maxDelay(); -                    src_wires[wire] = delay; - -                    return delay; -                }; +                arc_key arc; +                arc.net_info = net_info; +                arc.user_idx = user_idx;                  WireId cursor = dst_wire; -                while (src_wires.count(cursor) == 0) { +                wire_to_arc[cursor].insert(arc); + +                while (src_wire != cursor) {                      auto it = net_info->wires.find(cursor); -                    if (it == net_info->wires.end()) -                        goto check_next_user_for_existing_path; +                    if (it == net_info->wires.end()) { +                        arc_queue_insert(arc, src_wire, dst_wire); +                        break; +                    } +                      NPNR_ASSERT(it->second.pip != PipId());                      cursor = ctx->getPipSrcWire(it->second.pip); +                    wire_to_arc[cursor].insert(arc);                  } - -                register_existing_path(dst_wire); -            check_next_user_for_existing_path:;              } -            std::vector<WireId> ripup_wires; +            std::vector<WireId> unbind_wires; +              for (auto &it : net_info->wires) -                if (src_wires.count(it.first) == 0) -                    ripup_wires.push_back(it.first); +                if (it.second.strength < STRENGTH_LOCKED && wire_to_arc.count(it.first) == 0) +                    unbind_wires.push_back(it.first); -            for (auto &it : ripup_wires) { -                if (ctx->debug) -                    log("  Unbind dangling wire for net %s: %s\n", net_name.c_str(ctx), -                        ctx->getWireName(it).c_str(ctx)); +            for (auto it : unbind_wires)                  ctx->unbindWire(it); -            }          } +    } -        for (auto user_idx_it : users_array) { -            int user_idx = user_idx_it.second; - -            if (ctx->debug) -                log("  Route to: %s.%s.\n", net_info->users[user_idx].cell->name.c_str(ctx), -                    net_info->users[user_idx].port.c_str(ctx)); - -            auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); - -            if (dst_wire == WireId()) -                log_error("No wire found for port %s on destination cell %s.\n", -                          net_info->users[user_idx].port.c_str(ctx), net_info->users[user_idx].cell->name.c_str(ctx)); - -            if (ctx->debug) { -                log("    Destination wire: %s\n", ctx->getWireName(dst_wire).c_str(ctx)); -                log("    Path delay estimate: %.2f\n", float(ctx->estimateDelay(src_wire, dst_wire))); -            } - -            delay_t max_delay = 3 * ctx->estimateDelay(src_wire, dst_wire); -            route(src_wires, dst_wire, max_delay); - -            if (visited.count(dst_wire) == 0) { -                if (ctx->debug) -                    log("Failed to route %s -> %s.\n", ctx->getWireName(src_wire).c_str(ctx), -                        ctx->getWireName(dst_wire).c_str(ctx)); -                else if (ripup) -                    log_info("Failed to route %s -> %s.\n", ctx->getWireName(src_wire).c_str(ctx), -                             ctx->getWireName(dst_wire).c_str(ctx)); -                ripup_net(ctx, net_name); -                failedDest = dst_wire; -                return; -            } - -            if (ctx->debug) -                log("    Final path delay: %.3f\n", ctx->getDelayNS(visited[dst_wire].delay)); -            maxDelay = fmaxf(maxDelay, visited[dst_wire].delay); - -            if (ctx->debug) -                log("    Route (from destination to source):\n"); - -            WireId cursor = dst_wire; - -            while (1) { -                if (ctx->debug) -                    log("    %8.3f %s\n", ctx->getDelayNS(visited[cursor].delay), ctx->getWireName(cursor).c_str(ctx)); - -                if (src_wires.count(cursor)) -                    break; - -                NetInfo *conflicting_wire_net = ctx->getConflictingWireNet(cursor); +    arc_key arc_queue_pop() +    { +        arc_entry entry = arc_queue.top(); +        arc_queue.pop(); +        queued_arcs.erase(entry.arc); +        return entry.arc; +    } -                if (conflicting_wire_net != nullptr) { -                    NPNR_ASSERT(ripup); -                    NPNR_ASSERT(conflicting_wire_net->name != net_name); +    bool route_arc(const arc_key &arc, bool ripup) +    { -                    ctx->unbindWire(cursor); -                    if (!ctx->checkWireAvail(cursor)) -                        ripup_net(ctx, conflicting_wire_net->name); +        NetInfo *net_info = arc.net_info; +        int user_idx = arc.user_idx; -                    rippedNets.insert(conflicting_wire_net->name); -                    scores.wireScores[cursor]++; -                    scores.netWireScores[std::make_pair(net_name, cursor)]++; -                    scores.netWireScores[std::make_pair(conflicting_wire_net->name, cursor)]++; -                } +        auto src_wire = ctx->getNetinfoSourceWire(net_info); +        auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); +        ripup_flag = false; -                PipId pip = visited[cursor].pip; -                NetInfo *conflicting_pip_net = ctx->getConflictingPipNet(pip); +        if (ctx->debug) { +            log("Routing arc %d on net %s (%d arcs total):\n", user_idx, net_info->name.c_str(ctx), int(net_info->users.size())); +            log("  source ... %s\n", ctx->getWireName(src_wire).c_str(ctx)); +            log("  sink ..... %s\n", ctx->getWireName(dst_wire).c_str(ctx)); +        } -                if (conflicting_pip_net != nullptr) { -                    NPNR_ASSERT(ripup); -                    NPNR_ASSERT(conflicting_pip_net->name != net_name); +        // unbind wires that are currently used exclusively by this arc -                    if (ctx->getBoundPipNet(pip) == conflicting_pip_net) -                        ctx->unbindPip(pip); +        std::vector<WireId> unbind_wires; -                    if (!ctx->checkPipAvail(pip)) -                        ripup_net(ctx, conflicting_pip_net->name); +        for (auto &wire_it : net_info->wires) { +            auto wire = wire_it.first; +            auto wire_to_arc_it = wire_to_arc.find(wire); +            NPNR_ASSERT(wire_to_arc_it != wire_to_arc.end()); -                    rippedNets.insert(conflicting_pip_net->name); -                    scores.pipScores[visited[cursor].pip]++; -                    scores.netPipScores[std::make_pair(net_name, visited[cursor].pip)]++; -                    scores.netPipScores[std::make_pair(conflicting_pip_net->name, visited[cursor].pip)]++; -                } - -                ctx->bindPip(visited[cursor].pip, ctx->nets.at(net_name).get(), STRENGTH_WEAK); -                src_wires[cursor] = visited[cursor].delay; -                cursor = ctx->getPipSrcWire(visited[cursor].pip); -            } +            wire_to_arc_it->second.erase(arc); +            if (wire_to_arc_it->second.empty()) +                unbind_wires.push_back(wire);          } -        routedOkay = true; -    } -}; +        for (auto it : unbind_wires) +            ctx->unbindWire(it); -struct RouteJob -{ -    IdString net; -    int user_idx = -1; -    delay_t slack = 0; -    int randtag = 0; +        // reset wire queue -    struct Greater -    { -        bool operator()(const RouteJob &lhs, const RouteJob &rhs) const noexcept -        { -            return lhs.slack == rhs.slack ? lhs.randtag > rhs.randtag : lhs.slack > rhs.slack; +        if (!queue.empty()) { +            std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> new_queue; +            queue.swap(new_queue);          } -    }; -}; - -void addFullNetRouteJob(Context *ctx, const Router1Cfg &cfg, IdString net_name, -                        std::unordered_map<IdString, std::vector<bool>> &cache, -                        std::priority_queue<RouteJob, std::vector<RouteJob>, RouteJob::Greater> &queue) -{ -    NetInfo *net_info = ctx->nets.at(net_name).get(); - -    if (net_info->driver.cell == nullptr) -        return; +        visited.clear(); -    auto src_wire = ctx->getNetinfoSourceWire(net_info); +        int visitCnt = 0; +        int maxVisitCnt = INT_MAX; +        delay_t best_est = 0; -    if (src_wire == WireId()) -        log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx), -                  net_info->driver.cell->name.c_str(ctx)); +        { +            QueuedWire qw; +            qw.wire = src_wire; +            qw.pip = PipId(); +            qw.delay = ctx->getWireDelay(qw.wire).maxDelay(); +            qw.penalty = 0; +            if (cfg.useEstimate) { +                qw.togo = ctx->estimateDelay(qw.wire, dst_wire); +                best_est = qw.delay + qw.togo; +            } +            qw.randtag = ctx->rng(); -    auto &net_cache = cache[net_name]; +            queue.push(qw); +            visited[qw.wire] = qw; +        } -    if (net_cache.empty()) -        net_cache.resize(net_info->users.size()); +        while (visitCnt++ < maxVisitCnt && !queue.empty()) +        { +            QueuedWire qw = queue.top(); +            queue.pop(); -    RouteJob job; -    job.net = net_name; -    job.user_idx = -1; -    job.slack = 0; -    job.randtag = ctx->rng(); +            for (auto pip : ctx->getPipsDownhill(qw.wire)) { +                delay_t next_delay = qw.delay + ctx->getPipDelay(pip).maxDelay(); +                delay_t next_penalty = qw.penalty; -    bool got_slack = false; +                WireId next_wire = ctx->getPipDstWire(pip); +                next_delay += ctx->getWireDelay(next_wire).maxDelay(); -    for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { -        if (net_cache[user_idx]) -            continue; +                if (!ctx->checkWireAvail(next_wire)) { +                    NetInfo *ripupWireNet = ctx->getConflictingWireNet(next_wire); -        auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); +                    if (ripupWireNet == nullptr) +                        continue; -        if (dst_wire == WireId()) -            log_error("No wire found for port %s on destination cell %s.\n", net_info->users[user_idx].port.c_str(ctx), -                      net_info->users[user_idx].cell->name.c_str(ctx)); +                    if (ripupWireNet == net_info) { +                        next_penalty += cfg.wireReusePenalty; +                    } else { +                        if (!ripup) +                            continue; -        if (user_idx == 0) -            job.slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); -        else -            job.slack = std::min(job.slack, net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire)); +                        auto scores_it = wireScores.find(next_wire); +                        if (scores_it != wireScores.end()) +                            next_penalty += scores_it->second * cfg.wireRipupPenalty; +                    } +                } -        WireId cursor = dst_wire; -        while (src_wire != cursor) { -            auto it = net_info->wires.find(cursor); -            if (it == net_info->wires.end()) { -                if (!got_slack) -                    job.slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); -                else -                    job.slack = std::min(job.slack, -                                         net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire)); -                got_slack = true; -                break; -            } -            NPNR_ASSERT(it->second.pip != PipId()); -            cursor = ctx->getPipSrcWire(it->second.pip); -        } -    } +                if (!ctx->checkPipAvail(pip)) { +                    NetInfo *ripupPipNet = ctx->getConflictingPipNet(pip); -    queue.push(job); +                    if (ripupPipNet == nullptr) +                        continue; -    for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) -        net_cache[user_idx] = true; -} +                    if (ripupPipNet == net_info) { +                        next_penalty += cfg.pipReusePenalty; +                    } else { +                        if (!ripup) +                            continue; -void addNetRouteJobs(Context *ctx, const Router1Cfg &cfg, IdString net_name, -                     std::unordered_map<IdString, std::vector<bool>> &cache, -                     std::priority_queue<RouteJob, std::vector<RouteJob>, RouteJob::Greater> &queue) -{ -    NetInfo *net_info = ctx->nets.at(net_name).get(); +                        auto scores_it = pipScores.find(pip); +                        if (scores_it != pipScores.end()) +                            next_penalty += scores_it->second * cfg.pipRipupPenalty; +                    } +                } -#ifdef ARCH_ECP5 -    // ECP5 global nets currently appear part-unrouted due to arch database limitations -    // Don't touch them in the router -    if (net_info->is_global) -        return; +                if (visited.count(next_wire)) { +                    if (visited.at(next_wire).delay + visited.at(next_wire).penalty <= next_delay + next_penalty + ctx->getDelayEpsilon()) +                        continue; +#if 0 // FIXME +                    if (ctx->debug) +                        log("Found better route to %s. Old vs new delay estimate: %.3f %.3f\n", +                            ctx->getWireName(next_wire).c_str(), +                            ctx->getDelayNS(visited.at(next_wire).delay), +                            ctx->getDelayNS(next_delay));  #endif -    if (net_info->driver.cell == nullptr) -        return; - -    auto src_wire = ctx->getNetinfoSourceWire(net_info); - -    if (src_wire == WireId()) -        log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx), -                  net_info->driver.cell->name.c_str(ctx)); - -    auto &net_cache = cache[net_name]; - -    if (net_cache.empty()) -        net_cache.resize(net_info->users.size()); - -    for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { -        if (net_cache[user_idx]) -            continue; +                } -        auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); +                QueuedWire next_qw; +                next_qw.wire = next_wire; +                next_qw.pip = pip; +                next_qw.delay = next_delay; +                next_qw.penalty = next_penalty; +                if (cfg.useEstimate) { +                    next_qw.togo = ctx->estimateDelay(next_wire, dst_wire); +                    delay_t this_est = next_qw.delay + next_qw.togo; +                    if (this_est > best_est + cfg.estimatePrecision) +                        continue; +                    if (best_est > this_est) +                        best_est = this_est; +                } +                next_qw.randtag = ctx->rng(); -        if (dst_wire == WireId()) -            log_error("No wire found for port %s on destination cell %s.\n", net_info->users[user_idx].port.c_str(ctx), -                      net_info->users[user_idx].cell->name.c_str(ctx)); +                visited[next_qw.wire] = next_qw; +                queue.push(next_qw); -        WireId cursor = dst_wire; -        while (src_wire != cursor) { -            auto it = net_info->wires.find(cursor); -            if (it == net_info->wires.end()) { -                RouteJob job; -                job.net = net_name; -                job.user_idx = user_idx; -                job.slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); -                job.randtag = ctx->rng(); -                queue.push(job); -                net_cache[user_idx] = true; -                break; +                if (maxVisitCnt == INT_MAX && next_wire == dst_wire) +                    maxVisitCnt = 2*visitCnt;              } -            NPNR_ASSERT(it->second.pip != PipId()); -            cursor = ctx->getPipSrcWire(it->second.pip);          } -    } -} -void cleanupReroute(Context *ctx, const Router1Cfg &cfg, RipupScoreboard &scores, -                    std::unordered_set<IdString> &cleanupQueue, -                    std::priority_queue<RouteJob, std::vector<RouteJob>, RouteJob::Greater> &jobQueue, -                    int &totalVisitCnt, int &totalRevisitCnt, int &totalOvertimeRevisitCnt) -{ -    std::priority_queue<RouteJob, std::vector<RouteJob>, RouteJob::Greater> cleanupJobs; -    std::vector<NetInfo *> allNetinfos; +        if (ctx->debug) +            log("  total number of visited nodes: %d\n", visitCnt); -    for (auto net_name : cleanupQueue) { -        NetInfo *net_info = ctx->nets.at(net_name).get(); -        auto src_wire = ctx->getNetinfoSourceWire(net_info); +        if (visited.count(dst_wire) == 0) { +            if (ctx->debug) +                log("  no route found for this arc\n"); +            return false; +        } -        if (ctx->verbose) -            allNetinfos.push_back(net_info); +        WireId cursor = dst_wire; +        while (1) { +            if (ctx->debug) +                log("  node %s\n", ctx->getWireName(cursor).c_str(ctx)); -        std::unordered_map<WireId, int> useCounters; -        std::vector<int> candidateArcs; +            if (!ctx->checkWireAvail(cursor)) { +                NetInfo *ripupWireNet = ctx->getConflictingWireNet(cursor); +                NPNR_ASSERT(ripupWireNet != nullptr); -        for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { -            auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); +                if (ripupWireNet != net_info) +                    ripup_wire(cursor); +            } -            if (dst_wire == src_wire) -                continue; +            auto pip = visited[cursor].pip; -            auto cursor = dst_wire; -            useCounters[cursor]++; +            if (pip == PipId()) { +                NPNR_ASSERT(cursor == src_wire); +            } else { +                if (!ctx->checkPipAvail(pip)) { +                    NetInfo *ripupPipNet = ctx->getConflictingPipNet(pip); +                    NPNR_ASSERT(ripupPipNet != nullptr); -            while (cursor != src_wire) { -                auto it = net_info->wires.find(cursor); -                if (it == net_info->wires.end()) -                    break; -                cursor = ctx->getPipSrcWire(it->second.pip); -                useCounters[cursor]++; +                    if (ripupPipNet != net_info) +                        ripup_pip(pip); +                }              } -            if (cursor != src_wire) -                continue; - -            candidateArcs.push_back(user_idx); -        } +            if (ctx->checkWireAvail(cursor)) { +                if (pip == PipId()) +                    ctx->bindWire(cursor, net_info, STRENGTH_WEAK); +                else if (ctx->checkPipAvail(pip)) +                    ctx->bindPip(pip, net_info, STRENGTH_WEAK); +            } -        for (int user_idx : candidateArcs) { -            auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); +            wire_to_arc[cursor].insert(arc); -            if (useCounters.at(dst_wire) != 1) -                continue; +            if (pip == PipId()) +                break; -            RouteJob job; -            job.net = net_name; -            job.user_idx = user_idx; -            job.slack = net_info->users[user_idx].budget - ctx->estimateDelay(src_wire, dst_wire); -            job.randtag = ctx->rng(); -            cleanupJobs.push(job); +            cursor = ctx->getPipSrcWire(pip);          } -    } - -    log_info("running cleanup re-route of %d nets (%d arcs).\n", int(cleanupQueue.size()), int(cleanupJobs.size())); - -    cleanupQueue.clear(); - -    int visitCnt = 0, revisitCnt = 0, overtimeRevisitCnt = 0; -    int totalWireCountDelta = 0; - -    if (ctx->verbose) { -        for (auto it : allNetinfos) -            totalWireCountDelta -= it->wires.size(); -    } - -    while (!cleanupJobs.empty()) { -        RouteJob job = cleanupJobs.top(); -        cleanupJobs.pop(); - -        auto net_name = job.net; -        auto user_idx = job.user_idx; - -        NetInfo *net_info = ctx->nets.at(net_name).get(); -        auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); - -        ctx->unbindWire(dst_wire); - -        Router router(ctx, cfg, scores, net_name, user_idx, false, false); -        if (!router.routedOkay) -            log_error("Failed to re-route arc %d of net %s.\n", user_idx, net_name.c_str(ctx)); - -        visitCnt += router.visitCnt; -        revisitCnt += router.revisitCnt; -        overtimeRevisitCnt += router.overtimeRevisitCnt; -    } - -    if (ctx->verbose) { -        for (auto it : allNetinfos) -            totalWireCountDelta += it->wires.size(); +        if (ripup_flag) +            arcs_with_ripup++; +        else +            arcs_without_ripup++; -        log_info("  visited %d PIPs (%.2f%% revisits, %.2f%% overtime), %+d wires.\n", visitCnt, -                 (100.0 * revisitCnt) / visitCnt, (100.0 * overtimeRevisitCnt) / visitCnt, totalWireCountDelta); +        return true;      } - -    totalVisitCnt += visitCnt; -    totalRevisitCnt += revisitCnt; -    totalOvertimeRevisitCnt += overtimeRevisitCnt; -} +};  } // namespace @@ -703,258 +474,63 @@ Router1Cfg::Router1Cfg(Context *ctx) : Settings(ctx)      cleanupReroute = get<bool>("router1/cleanupReroute", true);      fullCleanupReroute = get<bool>("router1/fullCleanupReroute", true);      useEstimate = get<bool>("router1/useEstimate", true); + +    wireRipupPenalty = ctx->getRipupDelayPenalty(); +    pipRipupPenalty = ctx->getRipupDelayPenalty(); + +    wireReusePenalty = -wireRipupPenalty/8; +    pipReusePenalty = -pipRipupPenalty/8; + +    estimatePrecision = 100 * ctx->getRipupDelayPenalty();  }  bool router1(Context *ctx, const Router1Cfg &cfg)  {      try { -        int totalVisitCnt = 0, totalRevisitCnt = 0, totalOvertimeRevisitCnt = 0; -        delay_t ripup_penalty = ctx->getRipupDelayPenalty(); -        RipupScoreboard scores; -          log_break();          log_info("Routing..\n");          ctx->lock(); -        std::unordered_set<IdString> cleanupQueue; -        std::unordered_map<IdString, std::vector<bool>> jobCache; -        std::priority_queue<RouteJob, std::vector<RouteJob>, RouteJob::Greater> jobQueue; +        log_info("Setting up routing queue.\n"); -        for (auto &net_it : ctx->nets) -            addNetRouteJobs(ctx, cfg, net_it.first, jobCache, jobQueue); +        Router1 router(ctx, cfg); +        router.setup(); -        if (jobQueue.empty()) { -            log_info("found no unrouted source-sink pairs. no routing necessary.\n"); -            ctx->unlock(); -            return true; -        } +        log_info("Added %d arcs to routing queue.\n", int(router.arc_queue.size())); + +        int iter_cnt = 0; +        int last_arcs_with_ripup = 0; +        int last_arcs_without_ripup = 0; -        log_info("found %d unrouted source-sink pairs. starting routing procedure.\n", int(jobQueue.size())); +        while (!router.arc_queue.empty()) { +            if (++iter_cnt % 1000 == 0) { +                log_info("At iteration %d:\n", iter_cnt); +                log_info("  routed %d (%d) arcs with rip-up.\n", router.arcs_with_ripup, router.arcs_with_ripup - last_arcs_with_ripup); +                log_info("  routed %d (%d) arcs without rip-up.\n", router.arcs_without_ripup, router.arcs_without_ripup - last_arcs_without_ripup); +                log_info("  %d arcs remaining in routing queue.\n", int(router.arc_queue.size())); +                last_arcs_with_ripup = router.arcs_with_ripup; +                last_arcs_without_ripup = router.arcs_without_ripup; +            } -        int iterCnt = 0; +            arc_key arc = router.arc_queue_pop(); -        while (!jobQueue.empty()) { -            if (iterCnt == cfg.maxIterCnt) { -                log_warning("giving up after %d iterations.\n", iterCnt); -                log_info("Checksum: 0x%08x\n", ctx->checksum()); +            if (!router.route_arc(arc, true)) { +                log_warning("Failed to find a route for arc %d of net %s.\n", +                        arc.user_idx, arc.net_info->name.c_str(ctx));  #ifndef NDEBUG                  ctx->check();  #endif                  ctx->unlock();                  return false;              } - -            iterCnt++; -            if (ctx->verbose) -                log_info("-- %d --\n", iterCnt); - -            int visitCnt = 0, revisitCnt = 0, overtimeRevisitCnt = 0, jobCnt = 0, failedCnt = 0; - -            std::unordered_set<IdString> normalRouteNets, ripupQueue; - -            if (ctx->verbose || iterCnt == 1) -                log_info("routing queue contains %d jobs.\n", int(jobQueue.size())); -            else if (ctx->slack_redist_iter > 0 && iterCnt % ctx->slack_redist_iter == 0) -                assign_budget(ctx, true /* quiet */); - -            bool printNets = ctx->verbose && (jobQueue.size() < 10); - -            while (!jobQueue.empty()) { -                if (ctx->debug) -                    log("Next job slack: %f\n", double(jobQueue.top().slack)); - -                auto net_name = jobQueue.top().net; -                auto user_idx = jobQueue.top().user_idx; -                jobQueue.pop(); - -                if (cfg.fullCleanupReroute) -                    cleanupQueue.insert(net_name); - -                if (printNets) { -                    if (user_idx < 0) -                        log_info("  routing all %d users of net %s\n", int(ctx->nets.at(net_name)->users.size()), -                                 net_name.c_str(ctx)); -                    else -                        log_info("  routing user %d of net %s\n", user_idx, net_name.c_str(ctx)); -                } - -                Router router(ctx, cfg, scores, net_name, user_idx, false, false); - -                jobCnt++; -                visitCnt += router.visitCnt; -                revisitCnt += router.revisitCnt; -                overtimeRevisitCnt += router.overtimeRevisitCnt; - -                if (!router.routedOkay) { -                    if (printNets) -                        log_info("    failed to route to %s.\n", ctx->getWireName(router.failedDest).c_str(ctx)); -                    ripupQueue.insert(net_name); -                    failedCnt++; -                } else { -                    normalRouteNets.insert(net_name); -                } - -                if ((ctx->verbose || iterCnt == 1) && !printNets && (jobCnt % 100 == 0)) { -                    log_info("  processed %d jobs. (%d routed, %d failed)\n", jobCnt, jobCnt - failedCnt, failedCnt); -                    ctx->yield(); -                } -            } - -            NPNR_ASSERT(jobQueue.empty()); -            jobCache.clear(); - -            if ((ctx->verbose || iterCnt == 1) && (jobCnt % 100 != 0)) { -                log_info("  processed %d jobs. (%d routed, %d failed)\n", jobCnt, jobCnt - failedCnt, failedCnt); -                ctx->yield(); -            } - -            if (ctx->verbose) -                log_info("  visited %d PIPs (%.2f%% revisits, %.2f%% overtime revisits).\n", visitCnt, -                         (100.0 * revisitCnt) / visitCnt, (100.0 * overtimeRevisitCnt) / visitCnt); - -            if (!ripupQueue.empty()) { -                if (ctx->verbose || iterCnt == 1) -                    log_info("failed to route %d nets. re-routing in ripup mode.\n", int(ripupQueue.size())); - -                printNets = ctx->verbose && (ripupQueue.size() < 10); - -                visitCnt = 0; -                revisitCnt = 0; -                overtimeRevisitCnt = 0; -                int netCnt = 0; -                int ripCnt = 0; - -                std::vector<IdString> ripupArray(ripupQueue.begin(), ripupQueue.end()); -                ctx->sorted_shuffle(ripupArray); - -                for (auto net_name : ripupArray) { -                    if (cfg.cleanupReroute) -                        cleanupQueue.insert(net_name); - -                    if (printNets) -                        log_info("  routing net %s. (%d users)\n", net_name.c_str(ctx), -                                 int(ctx->nets.at(net_name)->users.size())); - -                    Router router(ctx, cfg, scores, net_name, -1, false, true, ripup_penalty); - -                    netCnt++; -                    visitCnt += router.visitCnt; -                    revisitCnt += router.revisitCnt; -                    overtimeRevisitCnt += router.overtimeRevisitCnt; - -                    if (!router.routedOkay) -                        log_error("Net %s is impossible to route.\n", net_name.c_str(ctx)); - -                    for (auto it : router.rippedNets) { -                        addFullNetRouteJob(ctx, cfg, it, jobCache, jobQueue); -                        if (cfg.cleanupReroute) -                            cleanupQueue.insert(it); -                    } - -                    if (printNets) { -                        if (router.rippedNets.size() < 10) { -                            log_info("    ripped up %d other nets:\n", int(router.rippedNets.size())); -                            for (auto n : router.rippedNets) -                                log_info("      %s (%d users)\n", n.c_str(ctx), int(ctx->nets.at(n)->users.size())); -                        } else { -                            log_info("    ripped up %d other nets.\n", int(router.rippedNets.size())); -                        } -                    } - -                    ripCnt += router.rippedNets.size(); - -                    if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) { -                        log_info("  routed %d nets, ripped %d nets.\n", netCnt, ripCnt); -                        ctx->yield(); -                    } -                } - -                if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) -                    log_info("  routed %d nets, ripped %d nets.\n", netCnt, ripCnt); - -                if (ctx->verbose) -                    log_info("  visited %d PIPs (%.2f%% revisits, %.2f%% overtime revisits).\n", visitCnt, -                             (100.0 * revisitCnt) / visitCnt, (100.0 * overtimeRevisitCnt) / visitCnt); - -                if (ctx->verbose && !jobQueue.empty()) -                    log_info("  ripped up %d previously routed nets. continue routing.\n", int(jobQueue.size())); -            } - -            if (!ctx->verbose) -                log_info("iteration %d: routed %d nets without ripup, routed %d nets with ripup.\n", iterCnt, -                         int(normalRouteNets.size()), int(ripupQueue.size())); - -            totalVisitCnt += visitCnt; -            totalRevisitCnt += revisitCnt; -            totalOvertimeRevisitCnt += overtimeRevisitCnt; - -            if (iterCnt == 8 || iterCnt == 16 || iterCnt == 32 || iterCnt == 64 || iterCnt == 128) -                ripup_penalty += ctx->getRipupDelayPenalty(); - -            if (jobQueue.empty() || (iterCnt % 5) == 0 || (cfg.fullCleanupReroute && iterCnt == 1)) -                cleanupReroute(ctx, cfg, scores, cleanupQueue, jobQueue, totalVisitCnt, totalRevisitCnt, -                               totalOvertimeRevisitCnt); - -            ctx->yield();          } -        log_info("routing complete after %d iterations.\n", iterCnt); +        log_info("At iteration %d:\n", iter_cnt); +        log_info("  routed %d (%d) arcs with rip-up.\n", router.arcs_with_ripup, router.arcs_with_ripup - last_arcs_with_ripup); +        log_info("  routed %d (%d) arcs without rip-up.\n", router.arcs_without_ripup, router.arcs_without_ripup - last_arcs_without_ripup); +        log_info("  %d arcs remaining in routing queue.\n", int(router.arc_queue.size())); -        log_info("visited %d PIPs (%.2f%% revisits, %.2f%% overtime revisits).\n", totalVisitCnt, -                 (100.0 * totalRevisitCnt) / totalVisitCnt, (100.0 * totalOvertimeRevisitCnt) / totalVisitCnt); - -        { -            float tns = 0; -            int tns_net_count = 0; -            int tns_arc_count = 0; -            for (auto &net_it : ctx->nets) { -                bool got_negative_slack = false; -                NetInfo *net_info = ctx->nets.at(net_it.first).get(); -                for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { -                    delay_t arc_delay = ctx->getNetinfoRouteDelay(net_info, net_info->users[user_idx]); -                    delay_t arc_budget = net_info->users[user_idx].budget; -                    delay_t arc_slack = arc_budget - arc_delay; -                    if (arc_slack < 0) { -                        if (!got_negative_slack) { -                            if (ctx->verbose) -                                log_info("net %s has negative slack arcs:\n", net_info->name.c_str(ctx)); -                            tns_net_count++; -                        } -                        if (ctx->verbose) -                            log_info("  arc %s -> %s has %f ns slack (delay %f, budget %f)\n", -                                     ctx->getWireName(ctx->getNetinfoSourceWire(net_info)).c_str(ctx), -                                     ctx->getWireName(ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx])) -                                             .c_str(ctx), -                                     ctx->getDelayNS(arc_slack), ctx->getDelayNS(arc_delay), -                                     ctx->getDelayNS(arc_budget)); -                        tns += ctx->getDelayNS(arc_slack); -                        tns_arc_count++; -                    } -                } -            } -            log_info("final tns with respect to arc budgets: %f ns (%d nets, %d arcs)\n", tns, tns_net_count, -                     tns_arc_count); -        } - -        NPNR_ASSERT(jobQueue.empty()); -        jobCache.clear(); - -        for (auto &net_it : ctx->nets) -            addNetRouteJobs(ctx, cfg, net_it.first, jobCache, jobQueue); - -#ifndef NDEBUG -        if (!jobQueue.empty()) { -            log_info("Design strangely still contains unrouted source-sink pairs:\n"); -            while (!jobQueue.empty()) { -                log_info("  user %d on net %s.\n", jobQueue.top().user_idx, jobQueue.top().net.c_str(ctx)); -                jobQueue.pop(); -            } -            log_info("Checksum: 0x%08x\n", ctx->checksum()); -            ctx->check(); -            ctx->unlock(); -            return false; -        } -#endif +        log_info("Routing finished after %d iterations.\n", iter_cnt);          log_info("Checksum: 0x%08x\n", ctx->checksum());  #ifndef NDEBUG @@ -975,30 +551,8 @@ bool router1(Context *ctx, const Router1Cfg &cfg)  bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay,                                    std::unordered_map<WireId, PipId> *route, bool useEstimate)  { -    RipupScoreboard scores; -    Router1Cfg cfg(this); -    cfg.useEstimate = useEstimate; - -    Router router(this, cfg, scores, src_wire, dst_wire); - -    if (!router.routedOkay) -        return false; - -    if (delay != nullptr) -        *delay = router.visited.at(dst_wire).delay; - -    if (route != nullptr) { -        WireId cursor = dst_wire; -        while (1) { -            PipId pip = router.visited.at(cursor).pip; -            (*route)[cursor] = pip; -            if (pip == PipId()) -                break; -            cursor = getPipSrcWire(pip); -        } -    } - -    return true; +    // FIXME +    return false;  }  NEXTPNR_NAMESPACE_END diff --git a/common/router1.h b/common/router1.h index a184cbe7..0c7699bc 100644 --- a/common/router1.h +++ b/common/router1.h @@ -33,6 +33,11 @@ struct Router1Cfg : Settings      bool cleanupReroute;      bool fullCleanupReroute;      bool useEstimate; +    delay_t wireRipupPenalty; +    delay_t pipRipupPenalty; +    delay_t wireReusePenalty; +    delay_t pipReusePenalty; +    delay_t estimatePrecision;  };  extern bool router1(Context *ctx, const Router1Cfg &cfg); | 
