From 6002a0a80ad2b7a300ea6cd3427dd942012de7d2 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 11 Nov 2018 19:48:15 +0100 Subject: [PATCH 1/8] clangformat Signed-off-by: Clifford Wolf --- common/router1.cc | 408 ++++++++++++++++++++++---------------------- ecp5/arch.h | 10 +- gui/designwidget.cc | 8 +- ice40/arch.h | 5 +- 4 files changed, 215 insertions(+), 216 deletions(-) diff --git a/common/router1.cc b/common/router1.cc index ad2b6757..41818800 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -33,15 +33,13 @@ struct arc_key NetInfo *net_info; int user_idx; - bool operator==(const arc_key &other) const { - return (net_info == other.net_info) && (user_idx == other.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()(arg.net_info); + std::size_t seed = std::hash()(arg.net_info); seed ^= std::hash()(arg.user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed; } @@ -55,10 +53,7 @@ struct arc_entry struct Greater { - bool operator()(const arc_entry &lhs, const arc_entry &rhs) const noexcept - { - return lhs.pri > rhs.pri; - } + bool operator()(const arc_entry &lhs, const arc_entry &rhs) const noexcept { return lhs.pri > rhs.pri; } }; }; @@ -99,13 +94,13 @@ struct Router1 std::priority_queue, QueuedWire::Greater> queue; std::unordered_map wireScores; - std::unordered_map netScores; + std::unordered_map netScores; int arcs_with_ripup = 0; int arcs_without_ripup = 0; bool ripup_flag; - Router1(Context *ctx, const Router1Cfg &cfg) : ctx(ctx), cfg(cfg) { } + Router1(Context *ctx, const Router1Cfg &cfg) : ctx(ctx), cfg(cfg) {} void arc_queue_insert(const arc_key &arc, WireId src_wire, WireId dst_wire) { @@ -245,15 +240,17 @@ struct Router1 { std::unordered_set valid_arcs; - for (auto &net_it : ctx->nets) - { + for (auto &net_it : ctx->nets) { NetInfo *net_info = net_it.second.get(); std::unordered_set valid_wires_for_net; if (skip_net(net_info)) continue; - // log("[check] net: %s\n", net_info->name.c_str(ctx)); +#if 0 + if (ctx->debug) + log("[check] net: %s\n", net_info->name.c_str(ctx)); +#endif auto src_wire = ctx->getNetinfoSourceWire(net_info); log_assert(src_wire != WireId()); @@ -267,10 +264,17 @@ struct Router1 arc.user_idx = user_idx; valid_arcs.insert(arc); - // log("[check] arc: %s %s\n", ctx->getWireName(src_wire).c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx)); +#if 0 + if (ctx->debug) + log("[check] arc: %s %s\n", ctx->getWireName(src_wire).c_str(ctx), + ctx->getWireName(dst_wire).c_str(ctx)); +#endif for (WireId wire : arc_to_wires[arc]) { - // log("[check] wire: %s\n", ctx->getWireName(wire).c_str(ctx)); +#if 0 + if (ctx->debug) + log("[check] wire: %s\n", ctx->getWireName(wire).c_str(ctx)); +#endif valid_wires_for_net.insert(wire); log_assert(wire_to_arcs[wire].count(arc)); log_assert(net_info->wires.count(wire)); @@ -295,11 +299,10 @@ struct Router1 void setup() { - std::unordered_map src_to_net; + std::unordered_map src_to_net; std::unordered_map dst_to_arc; - for (auto &net_it : ctx->nets) - { + for (auto &net_it : ctx->nets) { NetInfo *net_info = net_it.second.get(); if (skip_net(net_info)) @@ -316,26 +319,30 @@ struct Router1 ctx->nameOf(net_info), ctx->nameOf(src_to_net.at(src_wire))); if (dst_to_arc.count(src_wire)) - log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n", ctx->getWireName(src_wire).c_str(ctx), - ctx->nameOf(net_info), ctx->nameOf(dst_to_arc.at(src_wire).net_info), dst_to_arc.at(src_wire).user_idx); + log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n", + ctx->getWireName(src_wire).c_str(ctx), ctx->nameOf(net_info), + ctx->nameOf(dst_to_arc.at(src_wire).net_info), dst_to_arc.at(src_wire).user_idx); 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)); if (dst_to_arc.count(dst_wire)) { if (dst_to_arc.at(dst_wire).net_info == net_info) continue; - log_error("Found two arcs with same sink wire %s: %s (%d) vs %s (%d)\n", ctx->getWireName(dst_wire).c_str(ctx), - ctx->nameOf(net_info), user_idx, ctx->nameOf(dst_to_arc.at(dst_wire).net_info), dst_to_arc.at(dst_wire).user_idx); + log_error("Found two arcs with same sink wire %s: %s (%d) vs %s (%d)\n", + ctx->getWireName(dst_wire).c_str(ctx), ctx->nameOf(net_info), user_idx, + ctx->nameOf(dst_to_arc.at(dst_wire).net_info), dst_to_arc.at(dst_wire).user_idx); } if (src_to_net.count(dst_wire)) - log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n", ctx->getWireName(dst_wire).c_str(ctx), - ctx->nameOf(src_to_net.at(dst_wire)), ctx->nameOf(net_info), user_idx); + log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n", + ctx->getWireName(dst_wire).c_str(ctx), ctx->nameOf(src_to_net.at(dst_wire)), + ctx->nameOf(net_info), user_idx); arc_key arc; arc.net_info = net_info; @@ -390,7 +397,8 @@ struct Router1 ripup_flag = false; 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("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)); } @@ -443,8 +451,7 @@ struct Router1 visited[qw.wire] = qw; } - while (visitCnt++ < maxVisitCnt && !queue.empty()) - { + while (visitCnt++ < maxVisitCnt && !queue.empty()) { QueuedWire qw = queue.top(); queue.pop(); @@ -484,10 +491,12 @@ struct Router1 } } - if (conflictWireNet != nullptr && conflictPipWire != WireId() && conflictWireNet->wires.count(conflictPipWire)) + if (conflictWireNet != nullptr && conflictPipWire != WireId() && + conflictWireNet->wires.count(conflictPipWire)) conflictPipWire = WireId(); - if (conflictPipNet != nullptr && conflictWireWire != WireId() && conflictPipNet->wires.count(conflictWireWire)) + if (conflictPipNet != nullptr && conflictWireWire != WireId() && + conflictPipNet->wires.count(conflictWireWire)) conflictWireWire = WireId(); if (conflictWireWire == conflictPipWire) @@ -562,7 +571,7 @@ struct Router1 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/2 - cfg.estimatePrecision > best_est) + if (this_est / 2 - cfg.estimatePrecision > best_est) continue; if (best_est > this_est) best_est = this_est; @@ -583,7 +592,7 @@ struct Router1 if (next_wire == dst_wire) { if (maxVisitCnt == INT_MAX) - maxVisitCnt = 2*visitCnt; + maxVisitCnt = 2 * visitCnt; best_score = next_score - next_bonus; } } @@ -615,8 +624,8 @@ struct Router1 if (ctx->debug) log(" node %s\n", ctx->getWireName(cursor).c_str(ctx)); - if (pip == PipId()) - NPNR_ASSERT(cursor == src_wire); + if (pip == PipId()) + NPNR_ASSERT(cursor == src_wire); if (!net_info->wires.count(cursor) || net_info->wires.at(cursor).pip != pip) { if (!ctx->checkWireAvail(cursor)) { @@ -670,8 +679,8 @@ Router1Cfg::Router1Cfg(Context *ctx) : Settings(ctx) useEstimate = get("router1/useEstimate", true); wireRipupPenalty = ctx->getRipupDelayPenalty(); - netRipupPenalty = 10*ctx->getRipupDelayPenalty(); - reuseBonus = wireRipupPenalty/2; + netRipupPenalty = 10 * ctx->getRipupDelayPenalty(); + reuseBonus = wireRipupPenalty / 2; estimatePrecision = 100 * ctx->getRipupDelayPenalty(); } @@ -702,10 +711,9 @@ bool router1(Context *ctx, const Router1Cfg &cfg) while (!router.arc_queue.empty()) { if (++iter_cnt % 1000 == 0) { - log_info("%10d | %8d %10d | %4d %5d | %9d\n", - iter_cnt, router.arcs_with_ripup, router.arcs_without_ripup, - router.arcs_with_ripup - last_arcs_with_ripup, - router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size())); + log_info("%10d | %8d %10d | %4d %5d | %9d\n", iter_cnt, router.arcs_with_ripup, + router.arcs_without_ripup, router.arcs_with_ripup - last_arcs_with_ripup, + router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size())); last_arcs_with_ripup = router.arcs_with_ripup; last_arcs_without_ripup = router.arcs_without_ripup; #ifndef NDEBUG @@ -719,8 +727,8 @@ bool router1(Context *ctx, const Router1Cfg &cfg) arc_key arc = router.arc_queue_pop(); 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)); + 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 router.check(); ctx->check(); @@ -730,10 +738,9 @@ bool router1(Context *ctx, const Router1Cfg &cfg) } } - log_info("%10d | %8d %10d | %4d %5d | %9d\n", - iter_cnt, router.arcs_with_ripup, router.arcs_without_ripup, - router.arcs_with_ripup - last_arcs_with_ripup, - router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size())); + log_info("%10d | %8d %10d | %4d %5d | %9d\n", iter_cnt, router.arcs_with_ripup, router.arcs_without_ripup, + router.arcs_with_ripup - last_arcs_with_ripup, router.arcs_without_ripup - last_arcs_without_ripup, + int(router.arc_queue.size())); log_info("Routing complete.\n"); #ifndef NDEBUG @@ -758,165 +765,166 @@ bool router1(Context *ctx, const Router1Cfg &cfg) bool Context::checkRoutedDesign() const { - const Context *ctx = getCtx(); + const Context *ctx = getCtx(); - for (auto &net_it : ctx->nets) { - NetInfo *net_info = net_it.second.get(); + for (auto &net_it : ctx->nets) { + NetInfo *net_info = net_it.second.get(); + if (ctx->debug) + log("checking net %s\n", net_info->name.c_str(ctx)); + + if (net_info->users.empty()) { if (ctx->debug) - log("checking net %s\n", net_info->name.c_str(ctx)); - - if (net_info->users.empty()) { - if (ctx->debug) - log(" net without sinks\n"); - log_assert(net_info->wires.empty()); - continue; - } - - bool found_unrouted = false; - bool found_loop = false; - bool found_stub = false; - - struct ExtraWireInfo { - int order_num = 0; - std::unordered_set children; - }; - - std::unordered_map db; - - for (auto &it : net_info->wires) { - WireId w = it.first; - PipId p = it.second.pip; - - if (p != PipId()) { - log_assert(ctx->getPipDstWire(p) == w); - db[ctx->getPipSrcWire(p)].children.insert(w); - } - } - - auto src_wire = ctx->getNetinfoSourceWire(net_info); - log_assert(src_wire != WireId()); - - if (net_info->wires.count(src_wire) == 0) { - if (ctx->debug) - log(" source (%s) not bound to net\n", ctx->getWireName(src_wire).c_str(ctx)); - found_unrouted = true; - } - - std::unordered_map dest_wires; - 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]); - log_assert(dst_wire != WireId()); - dest_wires[dst_wire] = user_idx; - - if (net_info->wires.count(dst_wire) == 0) { - if (ctx->debug) - log(" sink %d (%s) not bound to net\n", user_idx, ctx->getWireName(dst_wire).c_str(ctx)); - found_unrouted = true; - } - } - - std::function setOrderNum; - std::unordered_set logged_wires; - - setOrderNum = [&](WireId w, int num) { - auto &db_entry = db[w]; - if (db_entry.order_num != 0) { - found_loop = true; - log(" %*s=> loop\n", 2*num, ""); - return; - } - db_entry.order_num = num; - for (WireId child : db_entry.children) { - if (ctx->debug) { - log(" %*s-> %s\n", 2*num, "", ctx->getWireName(child).c_str(ctx)); - logged_wires.insert(child); - } - setOrderNum(child, num+1); - } - if (db_entry.children.empty()) { - if (dest_wires.count(w) != 0) { - if (ctx->debug) - log(" %*s=> sink %d\n", 2*num, "", dest_wires.at(w)); - } else { - if (ctx->debug) - log(" %*s=> stub\n", 2*num, ""); - found_stub = true; - } - } - }; - - if (ctx->debug) { - log(" driver: %s\n", ctx->getWireName(src_wire).c_str(ctx)); - logged_wires.insert(src_wire); - } - setOrderNum(src_wire, 1); - - std::unordered_set dangling_wires; - - for (auto &it : db) { - auto &db_entry = it.second; - if (db_entry.order_num == 0) - dangling_wires.insert(it.first); - } - - if (ctx->debug) { - if (dangling_wires.empty()) { - log(" no dangling wires.\n"); - } else { - std::unordered_set root_wires = dangling_wires; - - for (WireId w : dangling_wires) { - for (WireId c : db[w].children) - root_wires.erase(c); - } - - for (WireId w : root_wires) { - log(" dangling wire: %s\n", ctx->getWireName(w).c_str(ctx)); - logged_wires.insert(w); - setOrderNum(w, 1); - } - - for (WireId w : dangling_wires) { - if (logged_wires.count(w) == 0) - log(" loop: %s -> %s\n", - ctx->getWireName(ctx->getPipSrcWire(net_info->wires.at(w).pip)).c_str(ctx), - ctx->getWireName(w).c_str(ctx)); - } - } - } - - bool fail = false; - - if (found_unrouted) { - if (ctx->debug) - log("check failed: found unrouted arcs\n"); - fail = true; - } - - if (found_loop) { - if (ctx->debug) - log("check failed: found loops\n"); - fail = true; - } - - if (found_stub) { - if (ctx->debug) - log("check failed: found stubs\n"); - fail = true; - } - - if (!dangling_wires.empty()) { - if (ctx->debug) - log("check failed: found dangling wires\n"); - fail = true; - } - - if (fail) - return false; + log(" net without sinks\n"); + log_assert(net_info->wires.empty()); + continue; } - return true; + bool found_unrouted = false; + bool found_loop = false; + bool found_stub = false; + + struct ExtraWireInfo + { + int order_num = 0; + std::unordered_set children; + }; + + std::unordered_map db; + + for (auto &it : net_info->wires) { + WireId w = it.first; + PipId p = it.second.pip; + + if (p != PipId()) { + log_assert(ctx->getPipDstWire(p) == w); + db[ctx->getPipSrcWire(p)].children.insert(w); + } + } + + auto src_wire = ctx->getNetinfoSourceWire(net_info); + log_assert(src_wire != WireId()); + + if (net_info->wires.count(src_wire) == 0) { + if (ctx->debug) + log(" source (%s) not bound to net\n", ctx->getWireName(src_wire).c_str(ctx)); + found_unrouted = true; + } + + std::unordered_map dest_wires; + 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]); + log_assert(dst_wire != WireId()); + dest_wires[dst_wire] = user_idx; + + if (net_info->wires.count(dst_wire) == 0) { + if (ctx->debug) + log(" sink %d (%s) not bound to net\n", user_idx, ctx->getWireName(dst_wire).c_str(ctx)); + found_unrouted = true; + } + } + + std::function setOrderNum; + std::unordered_set logged_wires; + + setOrderNum = [&](WireId w, int num) { + auto &db_entry = db[w]; + if (db_entry.order_num != 0) { + found_loop = true; + log(" %*s=> loop\n", 2 * num, ""); + return; + } + db_entry.order_num = num; + for (WireId child : db_entry.children) { + if (ctx->debug) { + log(" %*s-> %s\n", 2 * num, "", ctx->getWireName(child).c_str(ctx)); + logged_wires.insert(child); + } + setOrderNum(child, num + 1); + } + if (db_entry.children.empty()) { + if (dest_wires.count(w) != 0) { + if (ctx->debug) + log(" %*s=> sink %d\n", 2 * num, "", dest_wires.at(w)); + } else { + if (ctx->debug) + log(" %*s=> stub\n", 2 * num, ""); + found_stub = true; + } + } + }; + + if (ctx->debug) { + log(" driver: %s\n", ctx->getWireName(src_wire).c_str(ctx)); + logged_wires.insert(src_wire); + } + setOrderNum(src_wire, 1); + + std::unordered_set dangling_wires; + + for (auto &it : db) { + auto &db_entry = it.second; + if (db_entry.order_num == 0) + dangling_wires.insert(it.first); + } + + if (ctx->debug) { + if (dangling_wires.empty()) { + log(" no dangling wires.\n"); + } else { + std::unordered_set root_wires = dangling_wires; + + for (WireId w : dangling_wires) { + for (WireId c : db[w].children) + root_wires.erase(c); + } + + for (WireId w : root_wires) { + log(" dangling wire: %s\n", ctx->getWireName(w).c_str(ctx)); + logged_wires.insert(w); + setOrderNum(w, 1); + } + + for (WireId w : dangling_wires) { + if (logged_wires.count(w) == 0) + log(" loop: %s -> %s\n", + ctx->getWireName(ctx->getPipSrcWire(net_info->wires.at(w).pip)).c_str(ctx), + ctx->getWireName(w).c_str(ctx)); + } + } + } + + bool fail = false; + + if (found_unrouted) { + if (ctx->debug) + log("check failed: found unrouted arcs\n"); + fail = true; + } + + if (found_loop) { + if (ctx->debug) + log("check failed: found loops\n"); + fail = true; + } + + if (found_stub) { + if (ctx->debug) + log("check failed: found stubs\n"); + fail = true; + } + + if (!dangling_wires.empty()) { + if (ctx->debug) + log("check failed: found dangling wires\n"); + fail = true; + } + + if (fail) + return false; + } + + return true; } bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay, diff --git a/ecp5/arch.h b/ecp5/arch.h index bd4881c2..9daae11d 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -619,10 +619,7 @@ struct Arch : BaseCtx return wire_to_net.at(wire); } - WireId getConflictingWireWire(WireId wire) const - { - return wire; - } + WireId getConflictingWireWire(WireId wire) const { return wire; } NetInfo *getConflictingWireNet(WireId wire) const { @@ -729,10 +726,7 @@ struct Arch : BaseCtx return pip_to_net.at(pip); } - WireId getConflictingPipWire(PipId pip) const - { - return WireId(); - } + WireId getConflictingPipWire(PipId pip) const { return WireId(); } NetInfo *getConflictingPipNet(PipId pip) const { diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 8a134c1f..4a1d5a8f 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -453,8 +453,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti addProperty(topItem, QVariant::String, "Type", ctx->getWireType(wire).c_str(ctx)); addProperty(topItem, QVariant::Bool, "Available", ctx->checkWireAvail(wire)); addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundWireNet(wire)), ElementType::NET); - addProperty(topItem, QVariant::String, "Conflicting Wire", ctx->getWireName(ctx->getConflictingWireWire(wire)).c_str(ctx), - ElementType::WIRE); + addProperty(topItem, QVariant::String, "Conflicting Wire", + ctx->getWireName(ctx->getConflictingWireWire(wire)).c_str(ctx), ElementType::WIRE); addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)), ElementType::NET); @@ -515,8 +515,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti addProperty(topItem, QVariant::String, "Type", ctx->getPipType(pip).c_str(ctx)); addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip)); addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundPipNet(pip)), ElementType::NET); - addProperty(topItem, QVariant::String, "Conflicting Wire", ctx->getWireName(ctx->getConflictingPipWire(pip)).c_str(ctx), - ElementType::WIRE); + addProperty(topItem, QVariant::String, "Conflicting Wire", + ctx->getWireName(ctx->getConflictingPipWire(pip)).c_str(ctx), ElementType::WIRE); addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingPipNet(pip)), ElementType::NET); addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx), diff --git a/ice40/arch.h b/ice40/arch.h index 2967ee1f..b992d192 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -566,10 +566,7 @@ struct Arch : BaseCtx return wire_to_net[wire.index]; } - WireId getConflictingWireWire(WireId wire) const - { - return wire; - } + WireId getConflictingWireWire(WireId wire) const { return wire; } NetInfo *getConflictingWireNet(WireId wire) const { From e0fe52360621a51dc07f005dbe461db21c07f276 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 12 Nov 2018 11:23:31 +0000 Subject: [PATCH 2/8] Fix router1 check for ECP5 Signed-off-by: David Shah --- common/router1.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/router1.cc b/common/router1.cc index 41818800..7eb02370 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -770,6 +770,11 @@ bool Context::checkRoutedDesign() const for (auto &net_it : ctx->nets) { NetInfo *net_info = net_it.second.get(); +#ifdef ARCH_ECP5 + if (net_info->is_global) + continue; +#endif + if (ctx->debug) log("checking net %s\n", net_info->name.c_str(ctx)); From 06e0e1ffeec9b06cecc213728c279b9235316df9 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 13 Nov 2018 05:03:46 +0100 Subject: [PATCH 3/8] Various router1 fixes, Add BelId/WireId/PipId::operator<() Signed-off-by: Clifford Wolf --- common/router1.cc | 75 +++++++++++++++++++++++++++++++++++++++-------- docs/archapi.md | 6 ++-- ecp5/archdefs.h | 4 +++ ice40/archdefs.h | 3 ++ 4 files changed, 72 insertions(+), 16 deletions(-) diff --git a/common/router1.cc b/common/router1.cc index 7eb02370..0814514d 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -34,6 +34,7 @@ struct arc_key int user_idx; bool operator==(const arc_key &other) const { return (net_info == other.net_info) && (user_idx == other.user_idx); } + bool operator<(const arc_key &other) const { return net_info == other.net_info ? user_idx < other.user_idx : net_info->name < other.net_info->name; } struct Hash { @@ -50,10 +51,16 @@ struct arc_entry { arc_key arc; delay_t pri; + int randtag = 0; - struct Greater + struct Less { - bool operator()(const arc_entry &lhs, const arc_entry &rhs) const noexcept { return lhs.pri > rhs.pri; } + bool operator()(const arc_entry &lhs, const arc_entry &rhs) const noexcept + { + if (lhs.pri != rhs.pri) + return lhs.pri < rhs.pri; + return lhs.randtag < rhs.randtag; + } }; }; @@ -85,7 +92,7 @@ struct Router1 Context *ctx; const Router1Cfg &cfg; - std::priority_queue, arc_entry::Greater> arc_queue; + std::priority_queue, arc_entry::Less> arc_queue; std::unordered_map> wire_to_arcs; std::unordered_map, arc_key::Hash> arc_to_wires; std::unordered_set queued_arcs; @@ -112,6 +119,14 @@ struct Router1 arc_entry entry; entry.arc = arc; entry.pri = pri; + entry.randtag = ctx->rng(); + +#if 0 + if (ctx->debug) + log("[arc_queue_insert] %s (%d) %s %s [%d %d]\n", ctx->nameOf(entry.arc.net_info), entry.arc.user_idx, + ctx->getWireName(src_wire).c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx), (int)entry.pri, + entry.randtag); +#endif arc_queue.push(entry); queued_arcs.insert(arc); @@ -134,6 +149,13 @@ struct Router1 arc_key arc_queue_pop() { arc_entry entry = arc_queue.top(); + +#if 0 + if (ctx->debug) + log("[arc_queue_pop] %s (%d) [%d %d]\n", ctx->nameOf(entry.arc.net_info), entry.arc.user_idx, + (int)entry.pri, entry.randtag); +#endif + arc_queue.pop(); queued_arcs.erase(entry.arc); return entry.arc; @@ -146,16 +168,25 @@ struct Router1 netScores[net]++; - auto net_wires_copy = net->wires; - for (auto &it : net_wires_copy) { - WireId w = it.first; + std::vector wires; + for (auto &it : net->wires) + wires.push_back(it.first); + ctx->sorted_shuffle(wires); + + for (WireId w : wires) { + std::vector arcs; for (auto &it : wire_to_arcs[w]) { arc_to_wires[it].erase(w); - arc_queue_insert(it); + arcs.push_back(it); } wire_to_arcs[w].clear(); + ctx->sorted_shuffle(arcs); + + for (auto &it : arcs) + arc_queue_insert(it); + if (ctx->debug) log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx)); @@ -178,12 +209,18 @@ struct Router1 if (n != nullptr) ripup_net(n); } else { + std::vector arcs; for (auto &it : wire_to_arcs[w]) { arc_to_wires[it].erase(w); - arc_queue_insert(it); + arcs.push_back(it); } wire_to_arcs[w].clear(); + ctx->sorted_shuffle(arcs); + + for (auto &it : arcs) + arc_queue_insert(it); + if (ctx->debug) log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx)); @@ -206,12 +243,18 @@ struct Router1 if (n != nullptr) ripup_net(n); } else { + std::vector arcs; for (auto &it : wire_to_arcs[w]) { arc_to_wires[it].erase(w); - arc_queue_insert(it); + arcs.push_back(it); } wire_to_arcs[w].clear(); + ctx->sorted_shuffle(arcs); + + for (auto &it : arcs) + arc_queue_insert(it); + if (ctx->debug) log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx)); @@ -302,8 +345,14 @@ struct Router1 std::unordered_map src_to_net; std::unordered_map dst_to_arc; - for (auto &net_it : ctx->nets) { - NetInfo *net_info = net_it.second.get(); + std::vector net_names; + for (auto &net_it : ctx->nets) + net_names.push_back(net_it.first); + + ctx->sorted_shuffle(net_names); + + for (IdString net_name : net_names) { + NetInfo *net_info = ctx->nets.at(net_name).get(); if (skip_net(net_info)) continue; @@ -591,8 +640,7 @@ struct Router1 queue.push(next_qw); if (next_wire == dst_wire) { - if (maxVisitCnt == INT_MAX) - maxVisitCnt = 2 * visitCnt; + maxVisitCnt = std::min(maxVisitCnt, 2 * visitCnt + (next_qw.penalty > 0 ? 100 : 0)); best_score = next_score - next_bonus; } } @@ -611,6 +659,7 @@ struct Router1 log(" final route delay: %8.2f\n", ctx->getDelayNS(visited[dst_wire].delay)); log(" final route penalty: %8.2f\n", ctx->getDelayNS(visited[dst_wire].penalty)); log(" final route bonus: %8.2f\n", ctx->getDelayNS(visited[dst_wire].bonus)); + log(" arc budget: %12.2f\n", ctx->getDelayNS(net_info->users[user_idx].budget)); } // bind resulting route (and maybe unroute other nets) diff --git a/docs/archapi.md b/docs/archapi.md index 85bc6ccd..40eabd9d 100644 --- a/docs/archapi.md +++ b/docs/archapi.md @@ -30,15 +30,15 @@ delay_t maxDelay() const { return delay; } ### BelId -A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash`. +A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash`. ### WireId -A type representing a wire name. `WireId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash`. +A type representing a wire name. `WireId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash`. ### PipId -A type representing a pip name. `PipId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash`. +A type representing a pip name. `PipId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash`. ### GroupId diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index b85852c2..01cbad46 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -75,6 +75,7 @@ struct Location bool operator==(const Location &other) const { return x == other.x && y == other.y; } bool operator!=(const Location &other) const { return x != other.x || y != other.y; } + bool operator<(const Location &other) const { return y == other.y ? x < other.x : y < other.y; } }; inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); } @@ -86,6 +87,7 @@ struct BelId bool operator==(const BelId &other) const { return index == other.index && location == other.location; } bool operator!=(const BelId &other) const { return index != other.index || location != other.location; } + bool operator<(const BelId &other) const { return location == other.location ? index < other.index : location < other.location; } }; struct WireId @@ -95,6 +97,7 @@ struct WireId bool operator==(const WireId &other) const { return index == other.index && location == other.location; } bool operator!=(const WireId &other) const { return index != other.index || location != other.location; } + bool operator<(const WireId &other) const { return location == other.location ? index < other.index : location < other.location; } }; struct PipId @@ -104,6 +107,7 @@ struct PipId bool operator==(const PipId &other) const { return index == other.index && location == other.location; } bool operator!=(const PipId &other) const { return index != other.index || location != other.location; } + bool operator<(const PipId &other) const { return location == other.location ? index < other.index : location < other.location; } }; struct GroupId diff --git a/ice40/archdefs.h b/ice40/archdefs.h index c04033e7..b9614c07 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -66,6 +66,7 @@ struct BelId bool operator==(const BelId &other) const { return index == other.index; } bool operator!=(const BelId &other) const { return index != other.index; } + bool operator<(const BelId &other) const { return index < other.index; } }; struct WireId @@ -74,6 +75,7 @@ struct WireId bool operator==(const WireId &other) const { return index == other.index; } bool operator!=(const WireId &other) const { return index != other.index; } + bool operator<(const WireId &other) const { return index < other.index; } }; struct PipId @@ -82,6 +84,7 @@ struct PipId bool operator==(const PipId &other) const { return index == other.index; } bool operator!=(const PipId &other) const { return index != other.index; } + bool operator<(const PipId &other) const { return index < other.index; } }; struct GroupId From 959d163ba71fd2fdf08911e9be47f4f1d60514e5 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 13 Nov 2018 14:27:23 +0000 Subject: [PATCH 4/8] ecp5: Improve delay estimates Signed-off-by: David Shah --- ecp5/arch.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 4a0b31b5..ffd6ebcd 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -400,7 +400,7 @@ BelId Arch::getBelByLocation(Loc loc) const delay_t Arch::estimateDelay(WireId src, WireId dst) const { - return 100 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y)); + return 170 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y)); } delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const @@ -409,7 +409,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const auto driver_loc = getBelLocation(driver.cell->bel); auto sink_loc = getBelLocation(sink.cell->bel); - return 100 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y)); + return 170 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y)); } bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; } From 23218b3378ec57915f321e22ae7060ea454b65aa Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 13 Nov 2018 16:08:04 +0100 Subject: [PATCH 5/8] Add some architecture API FAQ items Signed-off-by: Clifford Wolf --- docs/faq.md | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/docs/faq.md b/docs/faq.md index d440bba6..63869240 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -38,7 +38,93 @@ For nextpnr we are using the following terminology. Adding new architectures to nextpnr ----------------------------------- -TBD +### Implementing new architectures + +Each nextpnr architecture must implement the *nextpnr architecture API*. +See [archapi.md](archapi.md) for a complete reference of the architecture API. + +### Delay Estimates + +Each architecture must implement a `estimateDelay()` method that estimates the expected delay for a path from given `src` to `dst` wires. +*It is very important that this method slightly overestimates the expected delay.* Otherwise there will be performance issues with the router. + +The delays estimates returned by that method should also be as fine-grain as possible. It definitely pays off to spend some time improving the `estimateDelay()` +for your architecture once implementing small designs work. + +### Ripup Information + +The `getConflictingWireWire()`, `getConflictingWireNet()`, `getConflictingPipWire()`, and `getConflictingPipNet()` methods are used by the router +to determine which resources to rip up in order to make a given routing resource (wire or pip) available. + +The architecture must guanrantee that the following invariants hold. + +**Invariant 1:** + +``` + if (!ctx->checkWireAvail(wire)) { + WireId w = getConflictingWireWire(wire); + if (w != WireId()) { + ctx->unbindWire(w); + assert(ctx->checkWireAvail(wire)); + } + } +``` + +**Invariant 2:** + +``` + if (!ctx->checkWireAvail(wire)) { + NetInfo *n = getConflictingWireNet(wire); + if (n != nullptr) { + for (auto &it : n->wires) + ctx->unbindWire(it.first); + assert(ctx->checkWireAvail(wire)); + } + } +``` + +**Invariant 3:** + +``` + if (!ctx->checkPipAvail(pip)) { + WireId w = getConflictingPipWire(pip); + if (w != WireId()) { + ctx->unbindWire(w); + assert(ctx->checkPipAvail(pip)); + } + } +``` + +**Invariant 4:** + +``` + if (!ctx->checkPipAvail(pip)) { + NetInfo *n = getConflictingPipNet(pip); + if (n != nullptr) { + for (auto &it : n->wires) + ctx->unbindWire(it.first); + assert(ctx->checkPipAvail(pip)); + } + } +``` + +**Invariant 5:** + +``` + if (ctx->checkWireAvail(wire)) { + // bind is guaranteed to succeed + ctx->bindWire(wire, net, strength); + } +``` + +**Invariant 6:** + +``` + if (ctx->checkPipAvail(pip) && ctx->checkWireAvail(ctx->getPipDstWire(pip))) { + // bind is guaranteed to succeed + ctx->bindPip(pip, net, strength); + } +``` Nextpnr and other tools ----------------------- From e06eef375cf62ffd258a702a7275cd0da0e67382 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 13 Nov 2018 16:08:44 +0100 Subject: [PATCH 6/8] Add more nameOf() convenience methods Signed-off-by: Clifford Wolf --- common/nextpnr.cc | 24 ++++++++++++++++++++++++ common/nextpnr.h | 14 ++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 2a581cc6..903ab9e4 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -53,6 +53,30 @@ void IdString::initialize_add(const BaseCtx *ctx, const char *s, int idx) ctx->idstring_idx_to_str->push_back(&insert_rc.first->first); } +const char *BaseCtx::nameOfBel(BelId bel) const +{ + const Context *ctx = getCtx(); + return ctx->getBelName(bel).c_str(ctx); +} + +const char *BaseCtx::nameOfWire(WireId wire) const +{ + const Context *ctx = getCtx(); + return ctx->getWireName(wire).c_str(ctx); +} + +const char *BaseCtx::nameOfPip(PipId pip) const +{ + const Context *ctx = getCtx(); + return ctx->getPipName(pip).c_str(ctx); +} + +const char *BaseCtx::nameOfGroup(GroupId group) const +{ + const Context *ctx = getCtx(); + return ctx->getGroupName(group).c_str(ctx); +} + WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const { if (net_info->driver.cell == nullptr) diff --git a/common/nextpnr.h b/common/nextpnr.h index 5a0bd4b1..86e781ae 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -487,13 +487,23 @@ struct BaseCtx const Context *getCtx() const { return reinterpret_cast(this); } - template const char *nameOf(const T *obj) + const char *nameOf(IdString name) const + { + return name.c_str(this); + } + + template const char *nameOf(const T *obj) const { if (obj == nullptr) return ""; - return obj->name.c_str(getCtx()); + return obj->name.c_str(this); } + const char *nameOfBel(BelId bel) const; + const char *nameOfWire(WireId wire) const; + const char *nameOfPip(PipId pip) const; + const char *nameOfGroup(GroupId group) const; + // -------------------------------------------------------------- bool allUiReload = true; From 51b09f2407549ced10edc831ac5d0787e492713c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 13 Nov 2018 16:29:33 +0100 Subject: [PATCH 7/8] Improve router1 debug output, switch to nameOf APIs Signed-off-by: Clifford Wolf --- common/router1.cc | 85 ++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/common/router1.cc b/common/router1.cc index 0814514d..0481a95e 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -124,8 +124,7 @@ struct Router1 #if 0 if (ctx->debug) log("[arc_queue_insert] %s (%d) %s %s [%d %d]\n", ctx->nameOf(entry.arc.net_info), entry.arc.user_idx, - ctx->getWireName(src_wire).c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx), (int)entry.pri, - entry.randtag); + ctx->nameOfWire(src_wire), ctx->nameOfWire(dst_wire), (int)entry.pri, entry.randtag); #endif arc_queue.push(entry); @@ -164,7 +163,7 @@ struct Router1 void ripup_net(NetInfo *net) { if (ctx->debug) - log(" ripup net %s\n", net->name.c_str(ctx)); + log(" ripup net %s\n", ctx->nameOf(net)); netScores[net]++; @@ -188,7 +187,7 @@ struct Router1 arc_queue_insert(it); if (ctx->debug) - log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx)); + log(" unbind wire %s\n", ctx->nameOfWire(w)); ctx->unbindWire(w); wireScores[w]++; @@ -200,7 +199,7 @@ struct Router1 void ripup_wire(WireId wire, int extra_indent = 0) { if (ctx->debug) - log(" ripup wire %s\n", ctx->getWireName(wire).c_str(ctx)); + log(" ripup wire %s\n", ctx->nameOfWire(wire)); WireId w = ctx->getConflictingWireWire(wire); @@ -222,7 +221,7 @@ struct Router1 arc_queue_insert(it); if (ctx->debug) - log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx)); + log(" unbind wire %s\n", ctx->nameOfWire(w)); ctx->unbindWire(w); wireScores[w]++; @@ -234,7 +233,7 @@ struct Router1 void ripup_pip(PipId pip) { if (ctx->debug) - log(" ripup pip %s\n", ctx->getPipName(pip).c_str(ctx)); + log(" ripup pip %s\n", ctx->nameOfPip(pip)); WireId w = ctx->getConflictingPipWire(pip); @@ -256,7 +255,7 @@ struct Router1 arc_queue_insert(it); if (ctx->debug) - log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx)); + log(" unbind wire %s\n", ctx->nameOfWire(w)); ctx->unbindWire(w); wireScores[w]++; @@ -292,7 +291,7 @@ struct Router1 #if 0 if (ctx->debug) - log("[check] net: %s\n", net_info->name.c_str(ctx)); + log("[check] net: %s\n", ctx->nameOf(net_info)); #endif auto src_wire = ctx->getNetinfoSourceWire(net_info); @@ -309,14 +308,13 @@ struct Router1 valid_arcs.insert(arc); #if 0 if (ctx->debug) - log("[check] arc: %s %s\n", ctx->getWireName(src_wire).c_str(ctx), - ctx->getWireName(dst_wire).c_str(ctx)); + log("[check] arc: %s %s\n", ctx->nameOfWire(src_wire), ctx->nameOfWire(dst_wire)); #endif for (WireId wire : arc_to_wires[arc]) { #if 0 if (ctx->debug) - log("[check] wire: %s\n", ctx->getWireName(wire).c_str(ctx)); + log("[check] wire: %s\n", ctx->nameOfWire(wire)); #endif valid_wires_for_net.insert(wire); log_assert(wire_to_arcs[wire].count(arc)); @@ -360,16 +358,16 @@ struct Router1 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)); + log_error("No wire found for port %s on source cell %s.\n", ctx->nameOf(net_info->driver.port), + ctx->nameOf(net_info->driver.cell)); if (src_to_net.count(src_wire)) - log_error("Found two nets with same source wire %s: %s vs %s\n", ctx->getWireName(src_wire).c_str(ctx), + log_error("Found two nets with same source wire %s: %s vs %s\n", ctx->nameOfWire(src_wire), ctx->nameOf(net_info), ctx->nameOf(src_to_net.at(src_wire))); if (dst_to_arc.count(src_wire)) log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n", - ctx->getWireName(src_wire).c_str(ctx), ctx->nameOf(net_info), + ctx->nameOfWire(src_wire), ctx->nameOf(net_info), ctx->nameOf(dst_to_arc.at(src_wire).net_info), dst_to_arc.at(src_wire).user_idx); for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { @@ -377,20 +375,20 @@ struct Router1 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)); + ctx->nameOf(net_info->users[user_idx].port), + ctx->nameOf(net_info->users[user_idx].cell)); if (dst_to_arc.count(dst_wire)) { if (dst_to_arc.at(dst_wire).net_info == net_info) continue; log_error("Found two arcs with same sink wire %s: %s (%d) vs %s (%d)\n", - ctx->getWireName(dst_wire).c_str(ctx), ctx->nameOf(net_info), user_idx, + ctx->nameOfWire(dst_wire), ctx->nameOf(net_info), user_idx, ctx->nameOf(dst_to_arc.at(dst_wire).net_info), dst_to_arc.at(dst_wire).user_idx); } if (src_to_net.count(dst_wire)) log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n", - ctx->getWireName(dst_wire).c_str(ctx), ctx->nameOf(src_to_net.at(dst_wire)), + ctx->nameOfWire(dst_wire), ctx->nameOf(src_to_net.at(dst_wire)), ctx->nameOf(net_info), user_idx); arc_key arc; @@ -446,10 +444,10 @@ struct Router1 ripup_flag = false; if (ctx->debug) { - log("Routing arc %d on net %s (%d arcs total):\n", user_idx, net_info->name.c_str(ctx), + log("Routing arc %d on net %s (%d arcs total):\n", user_idx, ctx->nameOf(net_info), 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)); + log(" source ... %s\n", ctx->nameOfWire(src_wire)); + log(" sink ..... %s\n", ctx->nameOfWire(dst_wire)); } // unbind wires that are currently used exclusively by this arc @@ -463,7 +461,7 @@ struct Router1 arc_wires.erase(arc); if (arc_wires.empty()) { if (ctx->debug) - log(" unbind %s\n", ctx->getWireName(wire).c_str(ctx)); + log(" unbind %s\n", ctx->nameOfWire(wire)); ctx->unbindWire(wire); } } @@ -603,7 +601,7 @@ struct Router1 #if 0 if (ctx->debug) log("Found better route to %s. Old vs new delay estimate: %.3f (%.3f) %.3f (%.3f)\n", - ctx->getWireName(next_wire).c_str(ctx), + ctx->nameOfWire(next_wire), ctx->getDelayNS(old_score), ctx->getDelayNS(old_visited_it->second.delay), ctx->getDelayNS(next_score), @@ -630,8 +628,8 @@ struct Router1 #if 0 if (ctx->debug) log("%s -> %s: %.3f (%.3f)\n", - ctx->getWireName(qw.wire).c_str(ctx), - ctx->getWireName(next_wire).c_str(ctx), + ctx->nameOfWire(qw.wire), + ctx->nameOfWire(next_wire), ctx->getDelayNS(next_score), ctx->getDelayNS(next_delay)); #endif @@ -667,11 +665,17 @@ struct Router1 std::unordered_set unassign_wires = arc_to_wires[arc]; WireId cursor = dst_wire; + delay_t accumulated_path_delay = 0; while (1) { auto pip = visited[cursor].pip; - if (ctx->debug) - log(" node %s\n", ctx->getWireName(cursor).c_str(ctx)); + if (ctx->debug) { + log(" node %s (%+.1f)\n", ctx->nameOfWire(cursor), + ctx->getDelayNS(ctx->estimateDelay(cursor, dst_wire)) - ctx->getDelayNS(accumulated_path_delay)); + if (pip != PipId()) + accumulated_path_delay += ctx->getPipDelay(pip).maxDelay(); + accumulated_path_delay += ctx->getWireDelay(cursor).maxDelay(); + } if (pip == PipId()) NPNR_ASSERT(cursor == src_wire); @@ -689,11 +693,11 @@ struct Router1 if (pip == PipId()) { if (ctx->debug) - log(" bind wire %s\n", ctx->getWireName(cursor).c_str(ctx)); + log(" bind wire %s\n", ctx->nameOfWire(cursor)); ctx->bindWire(cursor, net_info, STRENGTH_WEAK); } else { if (ctx->debug) - log(" bind pip %s\n", ctx->getPipName(pip).c_str(ctx)); + log(" bind pip %s\n", ctx->nameOfPip(pip)); ctx->bindPip(pip, net_info, STRENGTH_WEAK); } } @@ -776,8 +780,7 @@ bool router1(Context *ctx, const Router1Cfg &cfg) arc_key arc = router.arc_queue_pop(); 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)); + log_warning("Failed to find a route for arc %d of net %s.\n", arc.user_idx, ctx->nameOf(arc.net_info)); #ifndef NDEBUG router.check(); ctx->check(); @@ -825,7 +828,7 @@ bool Context::checkRoutedDesign() const #endif if (ctx->debug) - log("checking net %s\n", net_info->name.c_str(ctx)); + log("checking net %s\n", ctx->nameOf(net_info)); if (net_info->users.empty()) { if (ctx->debug) @@ -861,7 +864,7 @@ bool Context::checkRoutedDesign() const if (net_info->wires.count(src_wire) == 0) { if (ctx->debug) - log(" source (%s) not bound to net\n", ctx->getWireName(src_wire).c_str(ctx)); + log(" source (%s) not bound to net\n", ctx->nameOfWire(src_wire)); found_unrouted = true; } @@ -873,7 +876,7 @@ bool Context::checkRoutedDesign() const if (net_info->wires.count(dst_wire) == 0) { if (ctx->debug) - log(" sink %d (%s) not bound to net\n", user_idx, ctx->getWireName(dst_wire).c_str(ctx)); + log(" sink %d (%s) not bound to net\n", user_idx, ctx->nameOfWire(dst_wire)); found_unrouted = true; } } @@ -891,7 +894,7 @@ bool Context::checkRoutedDesign() const db_entry.order_num = num; for (WireId child : db_entry.children) { if (ctx->debug) { - log(" %*s-> %s\n", 2 * num, "", ctx->getWireName(child).c_str(ctx)); + log(" %*s-> %s\n", 2 * num, "", ctx->nameOfWire(child)); logged_wires.insert(child); } setOrderNum(child, num + 1); @@ -909,7 +912,7 @@ bool Context::checkRoutedDesign() const }; if (ctx->debug) { - log(" driver: %s\n", ctx->getWireName(src_wire).c_str(ctx)); + log(" driver: %s\n", ctx->nameOfWire(src_wire)); logged_wires.insert(src_wire); } setOrderNum(src_wire, 1); @@ -934,7 +937,7 @@ bool Context::checkRoutedDesign() const } for (WireId w : root_wires) { - log(" dangling wire: %s\n", ctx->getWireName(w).c_str(ctx)); + log(" dangling wire: %s\n", ctx->nameOfWire(w)); logged_wires.insert(w); setOrderNum(w, 1); } @@ -942,8 +945,8 @@ bool Context::checkRoutedDesign() const for (WireId w : dangling_wires) { if (logged_wires.count(w) == 0) log(" loop: %s -> %s\n", - ctx->getWireName(ctx->getPipSrcWire(net_info->wires.at(w).pip)).c_str(ctx), - ctx->getWireName(w).c_str(ctx)); + ctx->nameOfWire(ctx->getPipSrcWire(net_info->wires.at(w).pip)), + ctx->nameOfWire(w)); } } } From caca485cfff7f999a19e86e2f00187550b0c92f4 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 13 Nov 2018 17:30:49 +0100 Subject: [PATCH 8/8] Minor router1 debug log improvements Signed-off-by: Clifford Wolf --- common/router1.cc | 10 ++++++++-- docs/faq.md | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/common/router1.cc b/common/router1.cc index 0481a95e..adad37e9 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -666,12 +666,18 @@ struct Router1 WireId cursor = dst_wire; delay_t accumulated_path_delay = 0; + delay_t last_path_delay_delta = 0; while (1) { auto pip = visited[cursor].pip; if (ctx->debug) { - log(" node %s (%+.1f)\n", ctx->nameOfWire(cursor), - ctx->getDelayNS(ctx->estimateDelay(cursor, dst_wire)) - ctx->getDelayNS(accumulated_path_delay)); + delay_t path_delay_delta = ctx->estimateDelay(cursor, dst_wire) - accumulated_path_delay; + + log(" node %s (%+.2f %+.2f)\n", ctx->nameOfWire(cursor), ctx->getDelayNS(path_delay_delta), + ctx->getDelayNS(path_delay_delta - last_path_delay_delta)); + + last_path_delay_delta = path_delay_delta; + if (pip != PipId()) accumulated_path_delay += ctx->getPipDelay(pip).maxDelay(); accumulated_path_delay += ctx->getWireDelay(cursor).maxDelay(); diff --git a/docs/faq.md b/docs/faq.md index 63869240..7b358187 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -46,7 +46,8 @@ See [archapi.md](archapi.md) for a complete reference of the architecture API. ### Delay Estimates Each architecture must implement a `estimateDelay()` method that estimates the expected delay for a path from given `src` to `dst` wires. -*It is very important that this method slightly overestimates the expected delay.* Otherwise there will be performance issues with the router. +*It is very important that this method slightly overestimates the expected delay.* Furthermore, it should overestimate the expected delay +by a slightly larger margin for longer paths than for shorter paths. Otherwise there will be performance issues with the router. The delays estimates returned by that method should also be as fine-grain as possible. It definitely pays off to spend some time improving the `estimateDelay()` for your architecture once implementing small designs work.