aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/router1.cc62
-rw-r--r--common/router1.h1
-rw-r--r--docs/archapi.md24
-rw-r--r--ecp5/arch.h5
-rw-r--r--generic/arch.cc2
-rw-r--r--generic/arch.h1
-rw-r--r--gui/designwidget.cc2
-rw-r--r--ice40/arch.h26
8 files changed, 87 insertions, 36 deletions
diff --git a/common/router1.cc b/common/router1.cc
index 14591232..f51155e8 100644
--- a/common/router1.cc
+++ b/common/router1.cc
@@ -100,6 +100,7 @@ struct Router1
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_without_ripup = 0;
@@ -146,21 +147,23 @@ 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);
+ ripup_wire(it.first, 4);
else
- ripup_pip(it.second.pip, true);
+ ripup_pip(it.second.pip, 4);
}
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(" %*sripup wire %s\n", extra_indent, "", ctx->getWireName(wire).c_str(ctx));
wireScores[wire]++;
@@ -182,14 +185,13 @@ struct Router1
ripup_flag = true;
}
- void ripup_pip(PipId pip, bool extra_indent = false)
+ void ripup_pip(PipId pip, int extra_indent = 0)
{
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(" %*sripup pip %s (%s)\n", extra_indent, "", ctx->getPipName(pip).c_str(ctx), ctx->getWireName(wire).c_str(ctx));
- wireScores[wire]++;
pipScores[pip]++;
if (ctx->getBoundPipNet(pip)) {
@@ -204,6 +206,7 @@ struct Router1
if (0) {
remove_wire_arcs:
+ wireScores[wire]++;
for (auto &it : wire_to_arcs[wire]) {
arc_to_wires[it].erase(wire);
arc_queue_insert(it);
@@ -213,9 +216,11 @@ remove_wire_arcs:
NetInfo *net = ctx->getConflictingPipNet(pip);
if (net != nullptr) {
- wireScores[wire] += net->wires.size();
- pipScores[pip] += net->wires.size();
- ripup_net(net);
+ wire = ctx->getConflictingPipWire(pip);
+ if (wire != WireId())
+ ripup_wire(wire, 2);
+ else
+ ripup_net(net);
}
ripup_flag = true;
@@ -436,11 +441,11 @@ remove_wire_arcs:
if (!ripup)
continue;
+ next_penalty += cfg.wireRipupPenalty;
+
auto scores_it = wireScores.find(next_wire);
if (scores_it != wireScores.end())
next_penalty += scores_it->second * cfg.wireRipupPenalty;
- else
- next_penalty += cfg.wireRipupPenalty;
}
}
@@ -451,16 +456,29 @@ remove_wire_arcs:
continue;
if (ripupPipNet == net_info) {
+ auto net_info_wire_it = net_info->wires.find(next_wire);
+ if (net_info_wire_it == net_info->wires.end() || net_info_wire_it->second.pip != pip)
+ goto pip_self_ripup;
next_bonus += cfg.pipReuseBonus;
} else {
+pip_self_ripup:
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;
+ next_penalty += cfg.pipRipupPenalty;
+
+ auto pip_scores_it = pipScores.find(pip);
+ if (pip_scores_it != pipScores.end())
+ next_penalty += pip_scores_it->second * cfg.pipRipupPenalty;
+
+ if (ctx->getConflictingPipWire(pip) == WireId()) {
+ auto net_scores_it = netScores.find(ripupPipNet);
+ if (net_scores_it != netScores.end())
+ next_penalty += net_scores_it->second * cfg.netRipupPenalty;
+
+ next_penalty += ripupPipNet->wires.size() * cfg.wireRipupPenalty;
+ next_penalty += (ripupPipNet->wires.size()-1) * cfg.pipRipupPenalty;
+ }
}
}
@@ -479,9 +497,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",
@@ -538,6 +553,12 @@ 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<WireId> unassign_wires = arc_to_wires[arc];
@@ -615,6 +636,7 @@ Router1Cfg::Router1Cfg(Context *ctx) : Settings(ctx)
wireRipupPenalty = ctx->getRipupDelayPenalty();
pipRipupPenalty = ctx->getRipupDelayPenalty();
+ netRipupPenalty = ctx->getRipupDelayPenalty();
wireReuseBonus = wireRipupPenalty/8;
pipReuseBonus = pipRipupPenalty/8;
diff --git a/common/router1.h b/common/router1.h
index 120bf30e..65975d53 100644
--- a/common/router1.h
+++ b/common/router1.h
@@ -35,6 +35,7 @@ struct Router1Cfg : Settings
bool useEstimate;
delay_t wireRipupPenalty;
delay_t pipRipupPenalty;
+ delay_t netRipupPenalty;
delay_t wireReuseBonus;
delay_t pipReuseBonus;
delay_t estimatePrecision;
diff --git a/docs/archapi.md b/docs/archapi.md
index 73443c15..1bfb7c5c 100644
--- a/docs/archapi.md
+++ b/docs/archapi.md
@@ -217,12 +217,12 @@ Return the net a wire is bound to.
### NetInfo \*getConflictingWireNet(WireId wire) const
-If this returns a non-nullptr, then unbinding that net
+If this returns a non-nullptr, then unbinding the wire from that net
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.
+or if there is no net that can be unbound from the wire to make it
+available.
### DelayInfo getWireDelay(WireId wire) const
@@ -289,11 +289,21 @@ Return the net this pip is bound to.
### NetInfo \*getConflictingPipNet(PipId pip) const
Return the net that needs to be unbound in order to make this
-pip available.
+pip available. Note that it may be neccessary to unroute that
+entire net to make the 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.
+This returns nullptr if the pip is already available,
+or if there is no single net that can be unrouted to make
+the pip available.
+
+### WireId getConflictingPipWire(PipId pip) const
+
+Return the single wire that needs to be unbound in order to make this pip
+available.
+
+This returns WireId() if the pip is already available,
+or if there is no single wire that can be unbound to make
+the pip available.
### const\_range\<PipId\> getPips() const
diff --git a/ecp5/arch.h b/ecp5/arch.h
index 583d539f..c9b1bf43 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -733,6 +733,11 @@ struct Arch : BaseCtx
return pip_to_net.at(pip);
}
+ WireId getConflictingPipWire(PipId pip) const
+ {
+ return WireId();
+ }
+
AllPipRange getPips() const
{
AllPipRange range;
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<PipId> &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..d64d03c3 100644
--- a/generic/arch.h
+++ b/generic/arch.h
@@ -187,6 +187,7 @@ struct Arch : BaseCtx
bool checkPipAvail(PipId pip) const;
NetInfo *getBoundPipNet(PipId pip) const;
NetInfo *getConflictingPipNet(PipId pip) const;
+ WireId getConflictingPipWire(PipId pip) const;
const std::vector<PipId> &getPips() const;
Loc getPipLocation(PipId pip) const;
WireId getPipSrcWire(PipId pip) const;
diff --git a/gui/designwidget.cc b/gui/designwidget.cc
index a45752fc..8eda8a76 100644
--- a/gui/designwidget.cc
+++ b/gui/designwidget.cc
@@ -515,6 +515,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundPipNet(pip)), ElementType::NET);
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingPipNet(pip)),
ElementType::NET);
+ addProperty(topItem, QVariant::String, "Conflicting Wire", ctx->getWireName(ctx->getConflictingPipWire(pip)).c_str(ctx),
+ ElementType::WIRE);
addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx),
ElementType::WIRE);
addProperty(topItem, QVariant::String, "Dest Wire", ctx->getWireName(ctx->getPipDstWire(pip)).c_str(ctx),
diff --git a/ice40/arch.h b/ice40/arch.h
index 27d5db9f..46f2b348 100644
--- a/ice40/arch.h
+++ b/ice40/arch.h
@@ -404,7 +404,7 @@ struct Arch : BaseCtx
std::vector<CellInfo *> bel_to_cell;
std::vector<NetInfo *> wire_to_net;
std::vector<NetInfo *> pip_to_net;
- std::vector<NetInfo *> switches_locked;
+ std::vector<WireId> 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);
@@ -608,14 +608,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 +628,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,7 +637,7 @@ 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);
}
@@ -647,7 +648,7 @@ struct Arch : BaseCtx
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)
+ if (switches_locked[pi.switch_index] != WireId())
return false;
if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) {
@@ -674,6 +675,13 @@ struct Arch : BaseCtx
NetInfo *getConflictingPipNet(PipId pip) const
{
NPNR_ASSERT(pip != PipId());
+ WireId wire = switches_locked[chip_info->pip_data[pip.index].switch_index];
+ return wire == WireId() ? nullptr : wire_to_net[wire.index];
+ }
+
+ WireId getConflictingPipWire(PipId pip) const
+ {
+ NPNR_ASSERT(pip != PipId());
return switches_locked[chip_info->pip_data[pip.index].switch_index];
}