diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 4e6407b2..2a581cc6 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -18,6 +18,7 @@ */ #include "nextpnr.h" +#include "log.h" 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), expr_str(expr_str), filename(filename), line(line) { + log_flush(); } void IdString::set(const BaseCtx *ctx, const std::string &s) diff --git a/common/router1.cc b/common/router1.cc index 958edf7d..ad2b6757 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -99,7 +99,7 @@ struct Router1 std::priority_queue, QueuedWire::Greater> queue; std::unordered_map wireScores; - std::unordered_map pipScores; + std::unordered_map netScores; int arcs_with_ripup = 0; int arcs_without_ripup = 0; @@ -124,6 +124,9 @@ struct Router1 void arc_queue_insert(const arc_key &arc) { + if (queued_arcs.count(arc)) + return; + NetInfo *net_info = arc.net_info; int user_idx = arc.user_idx; @@ -146,76 +149,79 @@ struct Router1 if (ctx->debug) log(" ripup net %s\n", net->name.c_str(ctx)); + netScores[net]++; + auto net_wires_copy = net->wires; for (auto &it : net_wires_copy) { - if (it.second.pip == PipId()) - ripup_wire(it.first, true); - else - ripup_pip(it.second.pip, true); + WireId w = it.first; + + for (auto &it : wire_to_arcs[w]) { + 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; } - void ripup_wire(WireId wire, bool extra_indent = false) + void ripup_wire(WireId wire, int extra_indent = 0) { 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)) { - for (auto &it : wire_to_arcs[wire]) { - arc_to_wires[it].erase(wire); + if (w == WireId()) { + NetInfo *n = ctx->getConflictingWireNet(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); } - wire_to_arcs[wire].clear(); - ctx->unbindWire(wire); - } + wire_to_arcs[w].clear(); - NetInfo *net = ctx->getConflictingWireNet(wire); - if (net != nullptr) { - wireScores[wire] += net->wires.size(); - ripup_net(net); + if (ctx->debug) + log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx)); + + ctx->unbindWire(w); + wireScores[w]++; } 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) - 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]++; - pipScores[pip]++; + WireId w = ctx->getConflictingPipWire(pip); - if (ctx->getBoundPipNet(pip)) { - ctx->unbindPip(pip); - goto remove_wire_arcs; - } - - if (ctx->getBoundWireNet(wire)) { - ctx->unbindWire(wire); - goto remove_wire_arcs; - } - - if (0) { -remove_wire_arcs: - for (auto &it : wire_to_arcs[wire]) { - arc_to_wires[it].erase(wire); + if (w == WireId()) { + NetInfo *n = ctx->getConflictingPipNet(pip); + if (n != nullptr) + ripup_net(n); + } else { + for (auto &it : wire_to_arcs[w]) { + arc_to_wires[it].erase(w); arc_queue_insert(it); } - wire_to_arcs[wire].clear(); - } + wire_to_arcs[w].clear(); - 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(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx)); + + ctx->unbindWire(w); + wireScores[w]++; } ripup_flag = true; @@ -247,6 +253,8 @@ remove_wire_arcs: if (skip_net(net_info)) continue; + // log("[check] net: %s\n", net_info->name.c_str(ctx)); + auto src_wire = ctx->getNetinfoSourceWire(net_info); log_assert(src_wire != WireId()); @@ -259,8 +267,10 @@ remove_wire_arcs: 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)); for (WireId wire : arc_to_wires[arc]) { + // log("[check] wire: %s\n", ctx->getWireName(wire).c_str(ctx)); valid_wires_for_net.insert(wire); log_assert(wire_to_arcs[wire].count(arc)); log_assert(net_info->wires.count(wire)); @@ -285,6 +295,9 @@ remove_wire_arcs: void setup() { + 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(); @@ -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), 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++) { 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), 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.net_info = net_info; arc.user_idx = user_idx; + dst_to_arc[dst_wire] = arc; + if (net_info->wires.count(src_wire) == 0) { arc_queue_insert(arc, src_wire, dst_wire); continue; @@ -332,6 +366,8 @@ remove_wire_arcs: } } + src_to_net[src_wire] = net_info; + std::vector unbind_wires; for (auto &it : net_info->wires) @@ -420,43 +456,74 @@ remove_wire_arcs: WireId next_wire = ctx->getPipDstWire(pip); next_delay += ctx->getWireDelay(next_wire).maxDelay(); - if (!ctx->checkWireAvail(next_wire)) { - NetInfo *ripupWireNet = ctx->getConflictingWireNet(next_wire); + WireId conflictWireWire = WireId(), conflictPipWire = WireId(); + NetInfo *conflictWireNet = nullptr, *conflictPipNet = nullptr; - if (ripupWireNet == nullptr) - continue; - - if (ripupWireNet == net_info) { - next_bonus += cfg.wireReuseBonus; - } else { + if (net_info->wires.count(next_wire) && net_info->wires.at(next_wire).pip == pip) { + next_bonus += cfg.reuseBonus; + } else { + if (!ctx->checkWireAvail(next_wire)) { if (!ripup) 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()) next_penalty += scores_it->second * cfg.wireRipupPenalty; - else - next_penalty += cfg.wireRipupPenalty; + next_penalty += cfg.wireRipupPenalty; } - } - if (!ctx->checkPipAvail(pip)) { - NetInfo *ripupPipNet = ctx->getConflictingPipNet(pip); + if (conflictPipWire != WireId()) { + 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) - continue; + if (conflictWireNet != nullptr) { + 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) { - next_bonus += cfg.pipReuseBonus; - } else { - if (!ripup) - continue; - - auto scores_it = pipScores.find(pip); - if (scores_it != pipScores.end()) - next_penalty += scores_it->second * cfg.pipRipupPenalty; - else - next_penalty += cfg.pipRipupPenalty; + if (conflictPipNet != nullptr) { + auto scores_it = netScores.find(conflictPipNet); + if (scores_it != netScores.end()) + next_penalty += scores_it->second * cfg.netRipupPenalty; + next_penalty += cfg.netRipupPenalty; + next_penalty += conflictPipNet->wires.size() * cfg.wireRipupPenalty; } } @@ -475,9 +542,6 @@ remove_wire_arcs: if (next_score + ctx->getDelayEpsilon() >= old_score) continue; - if (next_delay + ctx->getDelayEpsilon() >= old_delay) - continue; - #if 0 if (ctx->debug) 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; } + 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) std::unordered_set unassign_wires = arc_to_wires[arc]; WireId cursor = dst_wire; while (1) { + auto pip = visited[cursor].pip; + if (ctx->debug) log(" node %s\n", ctx->getWireName(cursor).c_str(ctx)); - if (!ctx->checkWireAvail(cursor)) { - NetInfo *ripupWireNet = ctx->getConflictingWireNet(cursor); - NPNR_ASSERT(ripupWireNet != nullptr); + if (pip == PipId()) + NPNR_ASSERT(cursor == src_wire); - if (ripupWireNet != net_info) { + if (!net_info->wires.count(cursor) || net_info->wires.at(cursor).pip != pip) { + if (!ctx->checkWireAvail(cursor)) { ripup_wire(cursor); NPNR_ASSERT(ctx->checkWireAvail(cursor)); } - } - auto pip = visited[cursor].pip; - - if (pip == PipId()) { - 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 (pip != PipId() && !ctx->checkPipAvail(pip)) { + ripup_pip(pip); + NPNR_ASSERT(ctx->checkPipAvail(pip)); } - } - if (ctx->checkWireAvail(cursor)) { if (pip == PipId()) { 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); - } else if (ctx->checkPipAvail(pip)) { + } else { 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); } } @@ -609,10 +670,8 @@ Router1Cfg::Router1Cfg(Context *ctx) : Settings(ctx) useEstimate = get("router1/useEstimate", true); wireRipupPenalty = ctx->getRipupDelayPenalty(); - pipRipupPenalty = ctx->getRipupDelayPenalty(); - - wireReuseBonus = wireRipupPenalty/8; - pipReuseBonus = pipRipupPenalty/8; + netRipupPenalty = 10*ctx->getRipupDelayPenalty(); + reuseBonus = wireRipupPenalty/2; 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())); last_arcs_with_ripup = router.arcs_with_ripup; last_arcs_without_ripup = router.arcs_without_ripup; +#ifndef NDEBUG router.check(); +#endif } + if (ctx->debug) + log("-- %d --\n", iter_cnt); + 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)); #ifndef NDEBUG + router.check(); ctx->check(); #endif ctx->unlock(); @@ -669,18 +734,17 @@ bool router1(Context *ctx, const Router1Cfg &cfg) 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 router.check(); + ctx->check(); + log_assert(ctx->checkRoutedDesign()); #endif - log_info("Routing complete.\n"); - ctx->checkRoutedDesign(); - log_info("Checksum: 0x%08x\n", ctx->checksum()); -#ifndef NDEBUG - ctx->check(); -#endif timing_analysis(ctx, true /* slack_histogram */, true /* print_path */); + ctx->unlock(); return true; } catch (log_execution_error_exception) { @@ -772,9 +836,11 @@ bool Context::checkRoutedDesign() const } if (db_entry.children.empty()) { 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 { - log(" %*s=> stub\n", 2*num, ""); + if (ctx->debug) + log(" %*s=> stub\n", 2*num, ""); found_stub = true; } } @@ -820,10 +886,34 @@ bool Context::checkRoutedDesign() const } } - log_assert(!found_unrouted); - log_assert(!found_loop); - log_assert(!found_stub); - log_assert(dangling_wires.empty()); + 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; diff --git a/common/router1.h b/common/router1.h index 120bf30e..80d7aa96 100644 --- a/common/router1.h +++ b/common/router1.h @@ -34,9 +34,8 @@ struct Router1Cfg : Settings bool fullCleanupReroute; bool useEstimate; delay_t wireRipupPenalty; - delay_t pipRipupPenalty; - delay_t wireReuseBonus; - delay_t pipReuseBonus; + delay_t netRipupPenalty; + delay_t reuseBonus; delay_t estimatePrecision; }; diff --git a/docs/archapi.md b/docs/archapi.md index 73443c15..85bc6ccd 100644 --- a/docs/archapi.md +++ b/docs/archapi.md @@ -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. -### 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. -This returns nullptr if the wire is already available, -or if there is no single net that can be unbound to make this -wire available. +### NetInfo \*getConflictingWireNet(WireId wire) const + +If this returns a non-nullptr, then unbinding that entire net +will make the given wire available. ### 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. +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 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 -Return the net that needs to be unbound in order to make this -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. +If this returns a non-nullptr, then unbinding that entire net +will make the given pip available. ### const\_range\ getPips() const diff --git a/ecp5/arch.h b/ecp5/arch.h index 583d539f..bd4881c2 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -619,6 +619,11 @@ struct Arch : BaseCtx return wire_to_net.at(wire); } + WireId getConflictingWireWire(WireId wire) const + { + return wire; + } + NetInfo *getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); @@ -724,6 +729,11 @@ struct Arch : BaseCtx return pip_to_net.at(pip); } + WireId getConflictingPipWire(PipId pip) const + { + return WireId(); + } + NetInfo *getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); diff --git a/generic/arch.cc b/generic/arch.cc index 3e95159a..4f2e07a2 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -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; } +WireId Arch::getConflictingPipWire(PipId pip) const { return pips.at(pip).bound_net ? pips.at(pip).dstWire : WireId(); } + const std::vector &Arch::getPips() const { return pip_ids; } Loc Arch::getPipLocation(PipId pip) const { return pips.at(pip).loc; } diff --git a/generic/arch.h b/generic/arch.h index 22966e2a..9311464e 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -172,6 +172,7 @@ struct Arch : BaseCtx void unbindWire(WireId wire); bool checkWireAvail(WireId wire) const; NetInfo *getBoundWireNet(WireId wire) const; + WireId getConflictingWireWire(WireId wire) const { return wire; } NetInfo *getConflictingWireNet(WireId wire) const; DelayInfo getWireDelay(WireId wire) const { return DelayInfo(); } const std::vector &getWires() const; @@ -186,6 +187,7 @@ struct Arch : BaseCtx void unbindPip(PipId pip); bool checkPipAvail(PipId pip) const; NetInfo *getBoundPipNet(PipId pip) const; + WireId getConflictingPipWire(PipId pip) const; NetInfo *getConflictingPipNet(PipId pip) const; const std::vector &getPips() const; Loc getPipLocation(PipId pip) const; diff --git a/gui/designwidget.cc b/gui/designwidget.cc index a45752fc..8a134c1f 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -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::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 Net", ctx->nameOf(ctx->getConflictingWireNet(wire)), 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::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 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 27d5db9f..2967ee1f 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -404,7 +404,7 @@ struct Arch : BaseCtx std::vector bel_to_cell; std::vector wire_to_net; std::vector pip_to_net; - std::vector switches_locked; + std::vector switches_locked; ArchArgs args; Arch(ArchArgs args); @@ -546,7 +546,7 @@ struct Arch : BaseCtx auto pip = it->second.pip; if (pip != PipId()) { 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); @@ -566,6 +566,11 @@ struct Arch : BaseCtx return wire_to_net[wire.index]; } + WireId getConflictingWireWire(WireId wire) const + { + return wire; + } + NetInfo *getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); @@ -608,14 +613,15 @@ struct Arch : BaseCtx { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] == nullptr); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr); - - pip_to_net[pip.index] = net; - switches_locked[chip_info->pip_data[pip.index].switch_index] = net; + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == WireId()); WireId dst; dst.index = chip_info->pip_data[pip.index].dst; 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; net->wires[dst].pip = pip; net->wires[dst].strength = strength; @@ -627,7 +633,7 @@ struct Arch : BaseCtx { NPNR_ASSERT(pip != PipId()); 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; 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] = 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); refreshUiWire(dst); } - bool checkPipAvail(PipId pip) const + bool ice40_pip_hard_unavail(PipId pip) const { NPNR_ASSERT(pip != PipId()); auto &pi = chip_info->pip_data[pip.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) { NPNR_ASSERT(si.bel >= 0); if (bel_to_cell[si.bel] != nullptr) - return false; + return true; } if (pi.flags & PipInfoPOD::FLAG_NOCARRY) { NPNR_ASSERT(si.bel >= 0); 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 @@ -671,10 +683,21 @@ struct Arch : BaseCtx 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 { - NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index]; + if (ice40_pip_hard_unavail(pip)) + 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