Merge branch 'router_improve' of https://github.com/YosysHQ/nextpnr into xc7-router_improve

This commit is contained in:
Eddie Hung 2018-11-11 10:13:13 -08:00
commit 19561fde52
9 changed files with 281 additions and 143 deletions

View File

@ -18,6 +18,7 @@
*/ */
#include "nextpnr.h" #include "nextpnr.h"
#include "log.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
@ -25,6 +26,7 @@ assertion_failure::assertion_failure(std::string msg, std::string expr_str, std:
: runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg), : runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg),
expr_str(expr_str), filename(filename), line(line) expr_str(expr_str), filename(filename), line(line)
{ {
log_flush();
} }
void IdString::set(const BaseCtx *ctx, const std::string &s) void IdString::set(const BaseCtx *ctx, const std::string &s)

View File

@ -99,7 +99,7 @@ struct Router1
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue; std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue;
std::unordered_map<WireId, int> wireScores; std::unordered_map<WireId, int> wireScores;
std::unordered_map<PipId, int> pipScores; std::unordered_map<NetInfo*, int> netScores;
int arcs_with_ripup = 0; int arcs_with_ripup = 0;
int arcs_without_ripup = 0; int arcs_without_ripup = 0;
@ -124,6 +124,9 @@ struct Router1
void arc_queue_insert(const arc_key &arc) void arc_queue_insert(const arc_key &arc)
{ {
if (queued_arcs.count(arc))
return;
NetInfo *net_info = arc.net_info; NetInfo *net_info = arc.net_info;
int user_idx = arc.user_idx; int user_idx = arc.user_idx;
@ -146,76 +149,79 @@ struct Router1
if (ctx->debug) if (ctx->debug)
log(" ripup net %s\n", net->name.c_str(ctx)); log(" ripup net %s\n", net->name.c_str(ctx));
netScores[net]++;
auto net_wires_copy = net->wires; auto net_wires_copy = net->wires;
for (auto &it : net_wires_copy) { for (auto &it : net_wires_copy) {
if (it.second.pip == PipId()) WireId w = it.first;
ripup_wire(it.first, true);
else for (auto &it : wire_to_arcs[w]) {
ripup_pip(it.second.pip, true); arc_to_wires[it].erase(w);
arc_queue_insert(it);
}
wire_to_arcs[w].clear();
if (ctx->debug)
log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx));
ctx->unbindWire(w);
wireScores[w]++;
} }
ripup_flag = true; ripup_flag = true;
} }
void ripup_wire(WireId wire, bool extra_indent = false) void ripup_wire(WireId wire, int extra_indent = 0)
{ {
if (ctx->debug) if (ctx->debug)
log(" %sripup wire %s\n", extra_indent ? " " : "", ctx->getWireName(wire).c_str(ctx)); log(" ripup wire %s\n", ctx->getWireName(wire).c_str(ctx));
wireScores[wire]++; WireId w = ctx->getConflictingWireWire(wire);
if (ctx->getBoundWireNet(wire)) { if (w == WireId()) {
for (auto &it : wire_to_arcs[wire]) { NetInfo *n = ctx->getConflictingWireNet(wire);
arc_to_wires[it].erase(wire); if (n != nullptr)
ripup_net(n);
} else {
for (auto &it : wire_to_arcs[w]) {
arc_to_wires[it].erase(w);
arc_queue_insert(it); arc_queue_insert(it);
} }
wire_to_arcs[wire].clear(); wire_to_arcs[w].clear();
ctx->unbindWire(wire);
}
NetInfo *net = ctx->getConflictingWireNet(wire); if (ctx->debug)
if (net != nullptr) { log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx));
wireScores[wire] += net->wires.size();
ripup_net(net); ctx->unbindWire(w);
wireScores[w]++;
} }
ripup_flag = true; ripup_flag = true;
} }
void ripup_pip(PipId pip, bool extra_indent = false) void ripup_pip(PipId pip)
{ {
WireId wire = ctx->getPipDstWire(pip);
if (ctx->debug) if (ctx->debug)
log(" %sripup pip %s (%s)\n", extra_indent ? " " : "", ctx->getPipName(pip).c_str(ctx), ctx->getWireName(wire).c_str(ctx)); log(" ripup pip %s\n", ctx->getPipName(pip).c_str(ctx));
wireScores[wire]++; WireId w = ctx->getConflictingPipWire(pip);
pipScores[pip]++;
if (ctx->getBoundPipNet(pip)) { if (w == WireId()) {
ctx->unbindPip(pip); NetInfo *n = ctx->getConflictingPipNet(pip);
goto remove_wire_arcs; if (n != nullptr)
} ripup_net(n);
} else {
if (ctx->getBoundWireNet(wire)) { for (auto &it : wire_to_arcs[w]) {
ctx->unbindWire(wire); arc_to_wires[it].erase(w);
goto remove_wire_arcs;
}
if (0) {
remove_wire_arcs:
for (auto &it : wire_to_arcs[wire]) {
arc_to_wires[it].erase(wire);
arc_queue_insert(it); arc_queue_insert(it);
} }
wire_to_arcs[wire].clear(); wire_to_arcs[w].clear();
}
NetInfo *net = ctx->getConflictingPipNet(pip); if (ctx->debug)
if (net != nullptr) { log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx));
wireScores[wire] += net->wires.size();
pipScores[pip] += net->wires.size(); ctx->unbindWire(w);
ripup_net(net); wireScores[w]++;
} }
ripup_flag = true; ripup_flag = true;
@ -247,6 +253,8 @@ remove_wire_arcs:
if (skip_net(net_info)) if (skip_net(net_info))
continue; continue;
// log("[check] net: %s\n", net_info->name.c_str(ctx));
auto src_wire = ctx->getNetinfoSourceWire(net_info); auto src_wire = ctx->getNetinfoSourceWire(net_info);
log_assert(src_wire != WireId()); log_assert(src_wire != WireId());
@ -259,8 +267,10 @@ remove_wire_arcs:
arc.user_idx = user_idx; arc.user_idx = user_idx;
valid_arcs.insert(arc); valid_arcs.insert(arc);
// log("[check] arc: %s %s\n", ctx->getWireName(src_wire).c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx));
for (WireId wire : arc_to_wires[arc]) { for (WireId wire : arc_to_wires[arc]) {
// log("[check] wire: %s\n", ctx->getWireName(wire).c_str(ctx));
valid_wires_for_net.insert(wire); valid_wires_for_net.insert(wire);
log_assert(wire_to_arcs[wire].count(arc)); log_assert(wire_to_arcs[wire].count(arc));
log_assert(net_info->wires.count(wire)); log_assert(net_info->wires.count(wire));
@ -285,6 +295,9 @@ remove_wire_arcs:
void setup() void setup()
{ {
std::unordered_map<WireId, NetInfo*> src_to_net;
std::unordered_map<WireId, arc_key> dst_to_arc;
for (auto &net_it : ctx->nets) for (auto &net_it : ctx->nets)
{ {
NetInfo *net_info = net_it.second.get(); NetInfo *net_info = net_it.second.get();
@ -298,6 +311,14 @@ remove_wire_arcs:
log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx), 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)); net_info->driver.cell->name.c_str(ctx));
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),
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);
for (int user_idx = 0; user_idx < int(net_info->users.size()); 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]); auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]);
@ -305,10 +326,23 @@ remove_wire_arcs:
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)); 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);
}
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);
arc_key arc; arc_key arc;
arc.net_info = net_info; arc.net_info = net_info;
arc.user_idx = user_idx; arc.user_idx = user_idx;
dst_to_arc[dst_wire] = arc;
if (net_info->wires.count(src_wire) == 0) { if (net_info->wires.count(src_wire) == 0) {
arc_queue_insert(arc, src_wire, dst_wire); arc_queue_insert(arc, src_wire, dst_wire);
continue; continue;
@ -332,6 +366,8 @@ remove_wire_arcs:
} }
} }
src_to_net[src_wire] = net_info;
std::vector<WireId> unbind_wires; std::vector<WireId> unbind_wires;
for (auto &it : net_info->wires) for (auto &it : net_info->wires)
@ -420,43 +456,74 @@ remove_wire_arcs:
WireId next_wire = ctx->getPipDstWire(pip); WireId next_wire = ctx->getPipDstWire(pip);
next_delay += ctx->getWireDelay(next_wire).maxDelay(); next_delay += ctx->getWireDelay(next_wire).maxDelay();
if (!ctx->checkWireAvail(next_wire)) { WireId conflictWireWire = WireId(), conflictPipWire = WireId();
NetInfo *ripupWireNet = ctx->getConflictingWireNet(next_wire); NetInfo *conflictWireNet = nullptr, *conflictPipNet = nullptr;
if (ripupWireNet == nullptr) if (net_info->wires.count(next_wire) && net_info->wires.at(next_wire).pip == pip) {
continue; next_bonus += cfg.reuseBonus;
} else {
if (ripupWireNet == net_info) { if (!ctx->checkWireAvail(next_wire)) {
next_bonus += cfg.wireReuseBonus;
} else {
if (!ripup) if (!ripup)
continue; continue;
conflictWireWire = ctx->getConflictingWireWire(next_wire);
if (conflictWireWire == WireId()) {
conflictWireNet = ctx->getConflictingWireNet(next_wire);
if (conflictWireNet == nullptr)
continue;
}
}
auto scores_it = wireScores.find(next_wire); if (!ctx->checkPipAvail(pip)) {
if (!ripup)
continue;
conflictPipWire = ctx->getConflictingPipWire(pip);
if (conflictPipWire == WireId()) {
conflictPipNet = ctx->getConflictingPipNet(pip);
if (conflictPipNet == nullptr)
continue;
}
}
if (conflictWireNet != nullptr && conflictPipWire != WireId() && conflictWireNet->wires.count(conflictPipWire))
conflictPipWire = WireId();
if (conflictPipNet != nullptr && conflictWireWire != WireId() && conflictPipNet->wires.count(conflictWireWire))
conflictWireWire = WireId();
if (conflictWireWire == conflictPipWire)
conflictWireWire = WireId();
if (conflictWireNet == conflictPipNet)
conflictWireNet = nullptr;
if (conflictWireWire != WireId()) {
auto scores_it = wireScores.find(conflictWireWire);
if (scores_it != wireScores.end()) if (scores_it != wireScores.end())
next_penalty += scores_it->second * cfg.wireRipupPenalty; next_penalty += scores_it->second * cfg.wireRipupPenalty;
else next_penalty += cfg.wireRipupPenalty;
next_penalty += cfg.wireRipupPenalty;
} }
}
if (!ctx->checkPipAvail(pip)) { if (conflictPipWire != WireId()) {
NetInfo *ripupPipNet = ctx->getConflictingPipNet(pip); auto scores_it = wireScores.find(conflictPipWire);
if (scores_it != wireScores.end())
next_penalty += scores_it->second * cfg.wireRipupPenalty;
next_penalty += cfg.wireRipupPenalty;
}
if (ripupPipNet == nullptr) if (conflictWireNet != nullptr) {
continue; auto scores_it = netScores.find(conflictWireNet);
if (scores_it != netScores.end())
next_penalty += scores_it->second * cfg.netRipupPenalty;
next_penalty += cfg.netRipupPenalty;
next_penalty += conflictWireNet->wires.size() * cfg.wireRipupPenalty;
}
if (ripupPipNet == net_info) { if (conflictPipNet != nullptr) {
next_bonus += cfg.pipReuseBonus; auto scores_it = netScores.find(conflictPipNet);
} else { if (scores_it != netScores.end())
if (!ripup) next_penalty += scores_it->second * cfg.netRipupPenalty;
continue; next_penalty += cfg.netRipupPenalty;
next_penalty += conflictPipNet->wires.size() * cfg.wireRipupPenalty;
auto scores_it = pipScores.find(pip);
if (scores_it != pipScores.end())
next_penalty += scores_it->second * cfg.pipRipupPenalty;
else
next_penalty += cfg.pipRipupPenalty;
} }
} }
@ -475,9 +542,6 @@ remove_wire_arcs:
if (next_score + ctx->getDelayEpsilon() >= old_score) if (next_score + ctx->getDelayEpsilon() >= old_score)
continue; continue;
if (next_delay + ctx->getDelayEpsilon() >= old_delay)
continue;
#if 0 #if 0
if (ctx->debug) if (ctx->debug)
log("Found better route to %s. Old vs new delay estimate: %.3f (%.3f) %.3f (%.3f)\n", log("Found better route to %s. Old vs new delay estimate: %.3f (%.3f) %.3f (%.3f)\n",
@ -534,47 +598,44 @@ remove_wire_arcs:
return false; return false;
} }
if (ctx->debug) {
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));
}
// bind resulting route (and maybe unroute other nets) // bind resulting route (and maybe unroute other nets)
std::unordered_set<WireId> unassign_wires = arc_to_wires[arc]; std::unordered_set<WireId> unassign_wires = arc_to_wires[arc];
WireId cursor = dst_wire; WireId cursor = dst_wire;
while (1) { while (1) {
auto pip = visited[cursor].pip;
if (ctx->debug) if (ctx->debug)
log(" node %s\n", ctx->getWireName(cursor).c_str(ctx)); log(" node %s\n", ctx->getWireName(cursor).c_str(ctx));
if (!ctx->checkWireAvail(cursor)) { if (pip == PipId())
NetInfo *ripupWireNet = ctx->getConflictingWireNet(cursor); NPNR_ASSERT(cursor == src_wire);
NPNR_ASSERT(ripupWireNet != nullptr);
if (ripupWireNet != net_info) { if (!net_info->wires.count(cursor) || net_info->wires.at(cursor).pip != pip) {
if (!ctx->checkWireAvail(cursor)) {
ripup_wire(cursor); ripup_wire(cursor);
NPNR_ASSERT(ctx->checkWireAvail(cursor)); NPNR_ASSERT(ctx->checkWireAvail(cursor));
} }
}
auto pip = visited[cursor].pip; if (pip != PipId() && !ctx->checkPipAvail(pip)) {
ripup_pip(pip);
if (pip == PipId()) { NPNR_ASSERT(ctx->checkPipAvail(pip));
NPNR_ASSERT(cursor == src_wire);
} else {
if (!ctx->checkPipAvail(pip)) {
NetInfo *ripupPipNet = ctx->getConflictingPipNet(pip);
NPNR_ASSERT(ripupPipNet != nullptr);
if (ripupPipNet != net_info || net_info->wires.at(cursor).pip != pip)
ripup_pip(pip);
} }
}
if (ctx->checkWireAvail(cursor)) {
if (pip == PipId()) { if (pip == PipId()) {
if (ctx->debug) if (ctx->debug)
log(" bind %s\n", ctx->getWireName(cursor).c_str(ctx)); log(" bind wire %s\n", ctx->getWireName(cursor).c_str(ctx));
ctx->bindWire(cursor, net_info, STRENGTH_WEAK); ctx->bindWire(cursor, net_info, STRENGTH_WEAK);
} else if (ctx->checkPipAvail(pip)) { } else {
if (ctx->debug) if (ctx->debug)
log(" bind %s\n", ctx->getPipName(pip).c_str(ctx)); log(" bind pip %s\n", ctx->getPipName(pip).c_str(ctx));
ctx->bindPip(pip, net_info, STRENGTH_WEAK); ctx->bindPip(pip, net_info, STRENGTH_WEAK);
} }
} }
@ -609,10 +670,8 @@ Router1Cfg::Router1Cfg(Context *ctx) : Settings(ctx)
useEstimate = get<bool>("router1/useEstimate", true); useEstimate = get<bool>("router1/useEstimate", true);
wireRipupPenalty = ctx->getRipupDelayPenalty(); wireRipupPenalty = ctx->getRipupDelayPenalty();
pipRipupPenalty = ctx->getRipupDelayPenalty(); netRipupPenalty = 10*ctx->getRipupDelayPenalty();
reuseBonus = wireRipupPenalty/2;
wireReuseBonus = wireRipupPenalty/8;
pipReuseBonus = pipRipupPenalty/8;
estimatePrecision = 100 * ctx->getRipupDelayPenalty(); estimatePrecision = 100 * ctx->getRipupDelayPenalty();
} }
@ -649,15 +708,21 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size())); router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size()));
last_arcs_with_ripup = router.arcs_with_ripup; last_arcs_with_ripup = router.arcs_with_ripup;
last_arcs_without_ripup = router.arcs_without_ripup; last_arcs_without_ripup = router.arcs_without_ripup;
#ifndef NDEBUG
router.check(); router.check();
#endif
} }
if (ctx->debug)
log("-- %d --\n", iter_cnt);
arc_key arc = router.arc_queue_pop(); arc_key arc = router.arc_queue_pop();
if (!router.route_arc(arc, true)) { if (!router.route_arc(arc, true)) {
log_warning("Failed to find a route for arc %d of net %s.\n", log_warning("Failed to find a route for arc %d of net %s.\n",
arc.user_idx, arc.net_info->name.c_str(ctx)); arc.user_idx, arc.net_info->name.c_str(ctx));
#ifndef NDEBUG #ifndef NDEBUG
router.check();
ctx->check(); ctx->check();
#endif #endif
ctx->unlock(); ctx->unlock();
@ -669,18 +734,17 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
iter_cnt, router.arcs_with_ripup, router.arcs_without_ripup, iter_cnt, router.arcs_with_ripup, router.arcs_without_ripup,
router.arcs_with_ripup - last_arcs_with_ripup, router.arcs_with_ripup - last_arcs_with_ripup,
router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size())); router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size()));
log_info("Routing complete.\n");
#ifndef NDEBUG #ifndef NDEBUG
router.check(); router.check();
ctx->check();
log_assert(ctx->checkRoutedDesign());
#endif #endif
log_info("Routing complete.\n");
ctx->checkRoutedDesign();
log_info("Checksum: 0x%08x\n", ctx->checksum()); log_info("Checksum: 0x%08x\n", ctx->checksum());
#ifndef NDEBUG
ctx->check();
#endif
timing_analysis(ctx, true /* slack_histogram */, true /* print_path */); timing_analysis(ctx, true /* slack_histogram */, true /* print_path */);
ctx->unlock(); ctx->unlock();
return true; return true;
} catch (log_execution_error_exception) { } catch (log_execution_error_exception) {
@ -772,9 +836,11 @@ bool Context::checkRoutedDesign() const
} }
if (db_entry.children.empty()) { if (db_entry.children.empty()) {
if (dest_wires.count(w) != 0) { if (dest_wires.count(w) != 0) {
log(" %*s=> sink %d\n", 2*num, "", dest_wires.at(w)); if (ctx->debug)
log(" %*s=> sink %d\n", 2*num, "", dest_wires.at(w));
} else { } else {
log(" %*s=> stub\n", 2*num, ""); if (ctx->debug)
log(" %*s=> stub\n", 2*num, "");
found_stub = true; found_stub = true;
} }
} }
@ -820,10 +886,34 @@ bool Context::checkRoutedDesign() const
} }
} }
log_assert(!found_unrouted); bool fail = false;
log_assert(!found_loop);
log_assert(!found_stub); if (found_unrouted) {
log_assert(dangling_wires.empty()); 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; return true;

View File

@ -34,9 +34,8 @@ struct Router1Cfg : Settings
bool fullCleanupReroute; bool fullCleanupReroute;
bool useEstimate; bool useEstimate;
delay_t wireRipupPenalty; delay_t wireRipupPenalty;
delay_t pipRipupPenalty; delay_t netRipupPenalty;
delay_t wireReuseBonus; delay_t reuseBonus;
delay_t pipReuseBonus;
delay_t estimatePrecision; delay_t estimatePrecision;
}; };

View File

@ -215,14 +215,15 @@ Return true if the wire is available, i.e. can be bound to a net.
Return the net a wire is bound to. Return the net a wire is bound to.
### NetInfo \*getConflictingWireNet(WireId wire) const ### WireId getConflictingWireWire(WireId wire) const
If this returns a non-nullptr, then unbinding that net If this returns a non-WireId(), then unbinding that wire
will make the given wire available. will make the given wire available.
This returns nullptr if the wire is already available, ### NetInfo \*getConflictingWireNet(WireId wire) const
or if there is no single net that can be unbound to make this
wire available. If this returns a non-nullptr, then unbinding that entire net
will make the given wire available.
### DelayInfo getWireDelay(WireId wire) const ### DelayInfo getWireDelay(WireId wire) const
@ -282,18 +283,23 @@ This method must also update `NetInfo::wires`.
Returns true if the given pip is available to be bound to a net. Returns true if the given pip is available to be bound to a net.
Users must also check if the pip destination wire is available
with `checkWireAvail(getPipDstWire(pip))` before binding the
pip to a net.
### NetInfo \*getBoundPipNet(PipId pip) const ### NetInfo \*getBoundPipNet(PipId pip) const
Return the net this pip is bound to. Return the net this pip is bound to.
### WireId getConflictingPipWire(PipId pip) const
If this returns a non-WireId(), then unbinding that wire
will make the given pip available.
### NetInfo \*getConflictingPipNet(PipId pip) const ### NetInfo \*getConflictingPipNet(PipId pip) const
Return the net that needs to be unbound in order to make this If this returns a non-nullptr, then unbinding that entire net
pip available. will make the given pip available.
This does not need to (but may) return the conflicting wire if the conflict is
limited to the conflicting wire being bound to the destination wire for this
pip.
### const\_range\<PipId\> getPips() const ### const\_range\<PipId\> getPips() const

View File

@ -619,6 +619,11 @@ struct Arch : BaseCtx
return wire_to_net.at(wire); return wire_to_net.at(wire);
} }
WireId getConflictingWireWire(WireId wire) const
{
return wire;
}
NetInfo *getConflictingWireNet(WireId wire) const NetInfo *getConflictingWireNet(WireId wire) const
{ {
NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire != WireId());
@ -724,6 +729,11 @@ struct Arch : BaseCtx
return pip_to_net.at(pip); return pip_to_net.at(pip);
} }
WireId getConflictingPipWire(PipId pip) const
{
return WireId();
}
NetInfo *getConflictingPipNet(PipId pip) const NetInfo *getConflictingPipNet(PipId pip) const
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());

View File

@ -373,6 +373,8 @@ NetInfo *Arch::getBoundPipNet(PipId pip) const { return pips.at(pip).bound_net;
NetInfo *Arch::getConflictingPipNet(PipId pip) const { return pips.at(pip).bound_net; } NetInfo *Arch::getConflictingPipNet(PipId pip) const { return pips.at(pip).bound_net; }
WireId Arch::getConflictingPipWire(PipId pip) const { return pips.at(pip).bound_net ? pips.at(pip).dstWire : WireId(); }
const std::vector<PipId> &Arch::getPips() const { return pip_ids; } const std::vector<PipId> &Arch::getPips() const { return pip_ids; }
Loc Arch::getPipLocation(PipId pip) const { return pips.at(pip).loc; } Loc Arch::getPipLocation(PipId pip) const { return pips.at(pip).loc; }

View File

@ -172,6 +172,7 @@ struct Arch : BaseCtx
void unbindWire(WireId wire); void unbindWire(WireId wire);
bool checkWireAvail(WireId wire) const; bool checkWireAvail(WireId wire) const;
NetInfo *getBoundWireNet(WireId wire) const; NetInfo *getBoundWireNet(WireId wire) const;
WireId getConflictingWireWire(WireId wire) const { return wire; }
NetInfo *getConflictingWireNet(WireId wire) const; NetInfo *getConflictingWireNet(WireId wire) const;
DelayInfo getWireDelay(WireId wire) const { return DelayInfo(); } DelayInfo getWireDelay(WireId wire) const { return DelayInfo(); }
const std::vector<WireId> &getWires() const; const std::vector<WireId> &getWires() const;
@ -186,6 +187,7 @@ struct Arch : BaseCtx
void unbindPip(PipId pip); void unbindPip(PipId pip);
bool checkPipAvail(PipId pip) const; bool checkPipAvail(PipId pip) const;
NetInfo *getBoundPipNet(PipId pip) const; NetInfo *getBoundPipNet(PipId pip) const;
WireId getConflictingPipWire(PipId pip) const;
NetInfo *getConflictingPipNet(PipId pip) const; NetInfo *getConflictingPipNet(PipId pip) const;
const std::vector<PipId> &getPips() const; const std::vector<PipId> &getPips() const;
Loc getPipLocation(PipId pip) const; Loc getPipLocation(PipId pip) const;

View File

@ -453,6 +453,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
addProperty(topItem, QVariant::String, "Type", ctx->getWireType(wire).c_str(ctx)); addProperty(topItem, QVariant::String, "Type", ctx->getWireType(wire).c_str(ctx));
addProperty(topItem, QVariant::Bool, "Available", ctx->checkWireAvail(wire)); 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, "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 Net", ctx->nameOf(ctx->getConflictingWireNet(wire)), addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)),
ElementType::NET); ElementType::NET);
@ -513,6 +515,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
addProperty(topItem, QVariant::String, "Type", ctx->getPipType(pip).c_str(ctx)); addProperty(topItem, QVariant::String, "Type", ctx->getPipType(pip).c_str(ctx));
addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip)); 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, "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 Net", ctx->nameOf(ctx->getConflictingPipNet(pip)), addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingPipNet(pip)),
ElementType::NET); ElementType::NET);
addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx), addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx),

View File

@ -404,7 +404,7 @@ struct Arch : BaseCtx
std::vector<CellInfo *> bel_to_cell; std::vector<CellInfo *> bel_to_cell;
std::vector<NetInfo *> wire_to_net; std::vector<NetInfo *> wire_to_net;
std::vector<NetInfo *> pip_to_net; std::vector<NetInfo *> pip_to_net;
std::vector<NetInfo *> switches_locked; std::vector<WireId> switches_locked;
ArchArgs args; ArchArgs args;
Arch(ArchArgs args); Arch(ArchArgs args);
@ -546,7 +546,7 @@ struct Arch : BaseCtx
auto pip = it->second.pip; auto pip = it->second.pip;
if (pip != PipId()) { if (pip != PipId()) {
pip_to_net[pip.index] = nullptr; pip_to_net[pip.index] = nullptr;
switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; switches_locked[chip_info->pip_data[pip.index].switch_index] = WireId();
} }
net_wires.erase(it); net_wires.erase(it);
@ -566,6 +566,11 @@ struct Arch : BaseCtx
return wire_to_net[wire.index]; return wire_to_net[wire.index];
} }
WireId getConflictingWireWire(WireId wire) const
{
return wire;
}
NetInfo *getConflictingWireNet(WireId wire) const NetInfo *getConflictingWireNet(WireId wire) const
{ {
NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire != WireId());
@ -608,14 +613,15 @@ struct Arch : BaseCtx
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
NPNR_ASSERT(pip_to_net[pip.index] == nullptr); NPNR_ASSERT(pip_to_net[pip.index] == nullptr);
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == WireId());
pip_to_net[pip.index] = net;
switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
WireId dst; WireId dst;
dst.index = chip_info->pip_data[pip.index].dst; dst.index = chip_info->pip_data[pip.index].dst;
NPNR_ASSERT(wire_to_net[dst.index] == nullptr); NPNR_ASSERT(wire_to_net[dst.index] == nullptr);
pip_to_net[pip.index] = net;
switches_locked[chip_info->pip_data[pip.index].switch_index] = dst;
wire_to_net[dst.index] = net; wire_to_net[dst.index] = net;
net->wires[dst].pip = pip; net->wires[dst].pip = pip;
net->wires[dst].strength = strength; net->wires[dst].strength = strength;
@ -627,7 +633,7 @@ struct Arch : BaseCtx
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
NPNR_ASSERT(pip_to_net[pip.index] != nullptr); NPNR_ASSERT(pip_to_net[pip.index] != nullptr);
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != WireId());
WireId dst; WireId dst;
dst.index = chip_info->pip_data[pip.index].dst; dst.index = chip_info->pip_data[pip.index].dst;
@ -636,33 +642,39 @@ struct Arch : BaseCtx
pip_to_net[pip.index]->wires.erase(dst); pip_to_net[pip.index]->wires.erase(dst);
pip_to_net[pip.index] = nullptr; pip_to_net[pip.index] = nullptr;
switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; switches_locked[chip_info->pip_data[pip.index].switch_index] = WireId();
refreshUiPip(pip); refreshUiPip(pip);
refreshUiWire(dst); refreshUiWire(dst);
} }
bool checkPipAvail(PipId pip) const bool ice40_pip_hard_unavail(PipId pip) const
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
auto &pi = chip_info->pip_data[pip.index]; auto &pi = chip_info->pip_data[pip.index];
auto &si = chip_info->bits_info->switches[pi.switch_index]; auto &si = chip_info->bits_info->switches[pi.switch_index];
if (switches_locked[pi.switch_index] != nullptr)
return false;
if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) { if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) {
NPNR_ASSERT(si.bel >= 0); NPNR_ASSERT(si.bel >= 0);
if (bel_to_cell[si.bel] != nullptr) if (bel_to_cell[si.bel] != nullptr)
return false; return true;
} }
if (pi.flags & PipInfoPOD::FLAG_NOCARRY) { if (pi.flags & PipInfoPOD::FLAG_NOCARRY) {
NPNR_ASSERT(si.bel >= 0); NPNR_ASSERT(si.bel >= 0);
if (bel_carry[si.bel]) if (bel_carry[si.bel])
return false; return true;
} }
return true; return false;
}
bool checkPipAvail(PipId pip) const
{
if (ice40_pip_hard_unavail(pip))
return false;
auto &pi = chip_info->pip_data[pip.index];
return switches_locked[pi.switch_index] == WireId();
} }
NetInfo *getBoundPipNet(PipId pip) const NetInfo *getBoundPipNet(PipId pip) const
@ -671,10 +683,21 @@ struct Arch : BaseCtx
return pip_to_net[pip.index]; return pip_to_net[pip.index];
} }
WireId getConflictingPipWire(PipId pip) const
{
if (ice40_pip_hard_unavail(pip))
return WireId();
return switches_locked[chip_info->pip_data[pip.index].switch_index];
}
NetInfo *getConflictingPipNet(PipId pip) const NetInfo *getConflictingPipNet(PipId pip) const
{ {
NPNR_ASSERT(pip != PipId()); if (ice40_pip_hard_unavail(pip))
return switches_locked[chip_info->pip_data[pip.index].switch_index]; return nullptr;
WireId wire = switches_locked[chip_info->pip_data[pip.index].switch_index];
return wire == WireId() ? nullptr : wire_to_net[wire.index];
} }
AllPipRange getPips() const AllPipRange getPips() const