2018-06-10 00:19:20 +08:00
|
|
|
/*
|
|
|
|
* nextpnr -- Next Generation Place and Route
|
|
|
|
*
|
2018-06-22 22:19:17 +08:00
|
|
|
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
|
2018-06-10 00:19:20 +08:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2019-02-08 21:43:55 +08:00
|
|
|
#include <chrono>
|
2018-06-13 22:52:21 +08:00
|
|
|
#include <cmath>
|
2018-06-10 00:19:20 +08:00
|
|
|
#include <queue>
|
|
|
|
|
|
|
|
#include "log.h"
|
2018-07-12 00:04:09 +08:00
|
|
|
#include "router1.h"
|
2021-03-02 01:41:29 +08:00
|
|
|
#include "scope_lock.h"
|
2018-07-22 04:59:48 +08:00
|
|
|
#include "timing.h"
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-06-21 20:16:07 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
USING_NEXTPNR_NAMESPACE
|
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
struct arc_key
|
2018-06-21 20:08:45 +08:00
|
|
|
{
|
2018-11-10 00:00:45 +08:00
|
|
|
NetInfo *net_info;
|
2021-02-10 22:31:16 +08:00
|
|
|
// logical user cell port index
|
2018-11-10 00:00:45 +08:00
|
|
|
int user_idx;
|
2021-02-10 22:31:16 +08:00
|
|
|
// physical index into cell->bel pin mapping (usually 0)
|
|
|
|
unsigned phys_idx;
|
2018-11-10 00:00:45 +08:00
|
|
|
|
2021-02-10 22:31:16 +08:00
|
|
|
bool operator==(const arc_key &other) const
|
|
|
|
{
|
|
|
|
return (net_info == other.net_info) && (user_idx == other.user_idx) && (phys_idx == other.phys_idx);
|
|
|
|
}
|
2018-11-16 21:25:51 +08:00
|
|
|
bool operator<(const arc_key &other) const
|
|
|
|
{
|
2021-02-10 22:31:16 +08:00
|
|
|
return net_info == other.net_info
|
|
|
|
? (user_idx == other.user_idx ? phys_idx < other.phys_idx : user_idx < other.user_idx)
|
|
|
|
: net_info->name < other.net_info->name;
|
2018-11-16 21:25:51 +08:00
|
|
|
}
|
2018-11-10 00:00:45 +08:00
|
|
|
|
|
|
|
struct Hash
|
2018-06-21 20:08:45 +08:00
|
|
|
{
|
2018-11-10 00:00:45 +08:00
|
|
|
std::size_t operator()(const arc_key &arg) const noexcept
|
|
|
|
{
|
2018-11-12 02:48:15 +08:00
|
|
|
std::size_t seed = std::hash<NetInfo *>()(arg.net_info);
|
2018-11-10 00:00:45 +08:00
|
|
|
seed ^= std::hash<int>()(arg.user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
2021-02-10 22:31:16 +08:00
|
|
|
seed ^= std::hash<int>()(arg.phys_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
2018-11-10 00:00:45 +08:00
|
|
|
return seed;
|
|
|
|
}
|
|
|
|
};
|
2018-06-21 20:08:45 +08:00
|
|
|
};
|
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
struct arc_entry
|
2018-06-21 20:08:45 +08:00
|
|
|
{
|
2018-11-10 00:00:45 +08:00
|
|
|
arc_key arc;
|
|
|
|
delay_t pri;
|
2018-11-13 12:03:46 +08:00
|
|
|
int randtag = 0;
|
2018-11-10 00:00:45 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
struct Less
|
2018-06-21 20:08:45 +08:00
|
|
|
{
|
2018-11-13 12:03:46 +08:00
|
|
|
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;
|
|
|
|
}
|
2018-11-10 00:00:45 +08:00
|
|
|
};
|
2018-06-21 20:08:45 +08:00
|
|
|
};
|
2018-06-12 20:24:59 +08:00
|
|
|
|
2018-06-10 00:19:20 +08:00
|
|
|
struct QueuedWire
|
|
|
|
{
|
|
|
|
WireId wire;
|
|
|
|
PipId pip;
|
2018-06-13 22:52:21 +08:00
|
|
|
|
2018-11-10 05:39:39 +08:00
|
|
|
delay_t delay = 0, penalty = 0, bonus = 0, togo = 0;
|
2018-06-19 18:49:40 +08:00
|
|
|
int randtag = 0;
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-06-12 20:24:59 +08:00
|
|
|
struct Greater
|
2018-06-10 00:19:20 +08:00
|
|
|
{
|
2018-06-23 21:28:09 +08:00
|
|
|
bool operator()(const QueuedWire &lhs, const QueuedWire &rhs) const noexcept
|
2018-06-12 20:24:59 +08:00
|
|
|
{
|
2018-09-04 23:55:43 +08:00
|
|
|
delay_t l = lhs.delay + lhs.penalty + lhs.togo;
|
|
|
|
delay_t r = rhs.delay + rhs.penalty + rhs.togo;
|
2018-11-10 05:39:39 +08:00
|
|
|
NPNR_ASSERT(l >= 0);
|
|
|
|
NPNR_ASSERT(r >= 0);
|
|
|
|
l -= lhs.bonus;
|
|
|
|
r -= rhs.bonus;
|
2018-06-19 18:49:40 +08:00
|
|
|
return l == r ? lhs.randtag > rhs.randtag : l > r;
|
2018-06-12 20:24:59 +08:00
|
|
|
}
|
|
|
|
};
|
2018-06-10 00:19:20 +08:00
|
|
|
};
|
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
struct Router1
|
2018-06-21 20:08:45 +08:00
|
|
|
{
|
2018-06-20 19:32:50 +08:00
|
|
|
Context *ctx;
|
2018-08-02 19:58:23 +08:00
|
|
|
const Router1Cfg &cfg;
|
2018-06-21 20:08:45 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
std::priority_queue<arc_entry, std::vector<arc_entry>, arc_entry::Less> arc_queue;
|
2018-11-11 04:14:50 +08:00
|
|
|
std::unordered_map<WireId, std::unordered_set<arc_key, arc_key::Hash>> wire_to_arcs;
|
|
|
|
std::unordered_map<arc_key, std::unordered_set<WireId>, arc_key::Hash> arc_to_wires;
|
2018-11-10 00:00:45 +08:00
|
|
|
std::unordered_set<arc_key, arc_key::Hash> queued_arcs;
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-06-20 19:32:50 +08:00
|
|
|
std::unordered_map<WireId, QueuedWire> visited;
|
2018-11-10 00:00:45 +08:00
|
|
|
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue;
|
2018-06-23 21:16:24 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
std::unordered_map<WireId, int> wireScores;
|
2018-11-12 02:48:15 +08:00
|
|
|
std::unordered_map<NetInfo *, int> netScores;
|
2018-06-13 22:52:21 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
int arcs_with_ripup = 0;
|
|
|
|
int arcs_without_ripup = 0;
|
|
|
|
bool ripup_flag;
|
2018-06-14 00:28:02 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
Router1(Context *ctx, const Router1Cfg &cfg) : ctx(ctx), cfg(cfg) {}
|
2018-06-23 21:16:24 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
void arc_queue_insert(const arc_key &arc, WireId src_wire, WireId dst_wire)
|
|
|
|
{
|
|
|
|
if (queued_arcs.count(arc))
|
|
|
|
return;
|
2018-06-23 21:16:24 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
delay_t pri = ctx->estimateDelay(src_wire, dst_wire) - arc.net_info->users[arc.user_idx].budget;
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
arc_entry entry;
|
|
|
|
entry.arc = arc;
|
|
|
|
entry.pri = pri;
|
2018-11-13 12:03:46 +08:00
|
|
|
entry.randtag = ctx->rng();
|
2018-06-21 20:08:45 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
#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,
|
2018-11-13 23:29:33 +08:00
|
|
|
ctx->nameOfWire(src_wire), ctx->nameOfWire(dst_wire), (int)entry.pri, entry.randtag);
|
2018-11-13 12:03:46 +08:00
|
|
|
#endif
|
2018-06-20 19:32:50 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
arc_queue.push(entry);
|
|
|
|
queued_arcs.insert(arc);
|
|
|
|
}
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
void arc_queue_insert(const arc_key &arc)
|
2018-06-20 19:32:50 +08:00
|
|
|
{
|
2018-11-12 00:28:41 +08:00
|
|
|
if (queued_arcs.count(arc))
|
|
|
|
return;
|
2018-06-20 19:32:50 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
NetInfo *net_info = arc.net_info;
|
|
|
|
int user_idx = arc.user_idx;
|
2021-02-10 22:31:16 +08:00
|
|
|
unsigned phys_idx = arc.phys_idx;
|
2018-06-20 19:32:50 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
2021-02-10 22:31:16 +08:00
|
|
|
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], phys_idx);
|
2018-06-20 19:32:50 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
arc_queue_insert(arc, src_wire, dst_wire);
|
|
|
|
}
|
2018-06-20 19:32:50 +08:00
|
|
|
|
2018-11-10 21:00:36 +08:00
|
|
|
arc_key arc_queue_pop()
|
|
|
|
{
|
|
|
|
arc_entry entry = arc_queue.top();
|
2018-06-22 01:17:04 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
#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
|
2018-06-20 19:32:50 +08:00
|
|
|
|
2018-11-10 21:00:36 +08:00
|
|
|
arc_queue.pop();
|
|
|
|
queued_arcs.erase(entry.arc);
|
|
|
|
return entry.arc;
|
|
|
|
}
|
2018-06-22 01:17:04 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
void ripup_net(NetInfo *net)
|
|
|
|
{
|
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" ripup net %s\n", ctx->nameOf(net));
|
2018-06-20 19:32:50 +08:00
|
|
|
|
2018-11-11 18:34:38 +08:00
|
|
|
netScores[net]++;
|
2018-07-21 19:38:44 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
std::vector<WireId> wires;
|
|
|
|
for (auto &it : net->wires)
|
|
|
|
wires.push_back(it.first);
|
2018-06-23 21:58:24 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
ctx->sorted_shuffle(wires);
|
2018-06-23 21:58:24 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
for (WireId w : wires) {
|
|
|
|
std::vector<arc_key> arcs;
|
2018-11-12 00:28:41 +08:00
|
|
|
for (auto &it : wire_to_arcs[w]) {
|
|
|
|
arc_to_wires[it].erase(w);
|
2018-11-13 12:03:46 +08:00
|
|
|
arcs.push_back(it);
|
2018-11-12 00:28:41 +08:00
|
|
|
}
|
|
|
|
wire_to_arcs[w].clear();
|
2018-06-23 21:58:24 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
ctx->sorted_shuffle(arcs);
|
2018-06-20 19:32:50 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
for (auto &it : arcs)
|
|
|
|
arc_queue_insert(it);
|
2018-06-23 21:58:24 +08:00
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" unbind wire %s\n", ctx->nameOfWire(w));
|
2018-06-23 21:58:24 +08:00
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
ctx->unbindWire(w);
|
|
|
|
wireScores[w]++;
|
2018-06-20 19:32:50 +08:00
|
|
|
}
|
2018-06-23 21:58:24 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
ripup_flag = true;
|
2018-06-20 19:32:50 +08:00
|
|
|
}
|
|
|
|
|
2018-11-11 18:34:38 +08:00
|
|
|
void ripup_wire(WireId wire, int extra_indent = 0)
|
2018-06-20 19:32:50 +08:00
|
|
|
{
|
2018-11-10 00:00:45 +08:00
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" ripup wire %s\n", ctx->nameOfWire(wire));
|
2018-06-21 20:08:45 +08:00
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
WireId w = ctx->getConflictingWireWire(wire);
|
2018-06-20 19:32:50 +08:00
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
if (w == WireId()) {
|
|
|
|
NetInfo *n = ctx->getConflictingWireNet(wire);
|
|
|
|
if (n != nullptr)
|
|
|
|
ripup_net(n);
|
|
|
|
} else {
|
2018-11-13 12:03:46 +08:00
|
|
|
std::vector<arc_key> arcs;
|
2018-11-12 00:28:41 +08:00
|
|
|
for (auto &it : wire_to_arcs[w]) {
|
|
|
|
arc_to_wires[it].erase(w);
|
2018-11-13 12:03:46 +08:00
|
|
|
arcs.push_back(it);
|
2018-11-11 04:14:50 +08:00
|
|
|
}
|
2018-11-12 00:28:41 +08:00
|
|
|
wire_to_arcs[w].clear();
|
2018-06-20 19:32:50 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
ctx->sorted_shuffle(arcs);
|
2018-06-20 19:32:50 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
for (auto &it : arcs)
|
|
|
|
arc_queue_insert(it);
|
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" unbind wire %s\n", ctx->nameOfWire(w));
|
2018-11-12 00:28:41 +08:00
|
|
|
|
|
|
|
ctx->unbindWire(w);
|
|
|
|
wireScores[w]++;
|
2018-06-20 19:32:50 +08:00
|
|
|
}
|
2018-06-22 01:17:04 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
ripup_flag = true;
|
2018-06-20 19:32:50 +08:00
|
|
|
}
|
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
void ripup_pip(PipId pip)
|
2018-06-20 19:32:50 +08:00
|
|
|
{
|
2018-06-21 20:08:45 +08:00
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" ripup pip %s\n", ctx->nameOfPip(pip));
|
2018-06-21 01:22:03 +08:00
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
WireId w = ctx->getConflictingPipWire(pip);
|
2018-11-11 04:14:50 +08:00
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
if (w == WireId()) {
|
|
|
|
NetInfo *n = ctx->getConflictingPipNet(pip);
|
|
|
|
if (n != nullptr)
|
|
|
|
ripup_net(n);
|
|
|
|
} else {
|
2018-11-13 12:03:46 +08:00
|
|
|
std::vector<arc_key> arcs;
|
2018-11-12 00:28:41 +08:00
|
|
|
for (auto &it : wire_to_arcs[w]) {
|
|
|
|
arc_to_wires[it].erase(w);
|
2018-11-13 12:03:46 +08:00
|
|
|
arcs.push_back(it);
|
2018-11-11 04:14:50 +08:00
|
|
|
}
|
2018-11-12 00:28:41 +08:00
|
|
|
wire_to_arcs[w].clear();
|
2018-06-21 01:22:03 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
ctx->sorted_shuffle(arcs);
|
2018-06-21 01:22:03 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
for (auto &it : arcs)
|
|
|
|
arc_queue_insert(it);
|
2018-06-21 01:22:03 +08:00
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" unbind wire %s\n", ctx->nameOfWire(w));
|
2018-06-21 01:22:03 +08:00
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
ctx->unbindWire(w);
|
|
|
|
wireScores[w]++;
|
2018-06-21 01:22:03 +08:00
|
|
|
}
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
ripup_flag = true;
|
2018-06-20 19:32:50 +08:00
|
|
|
}
|
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
bool skip_net(NetInfo *net_info)
|
2018-06-14 21:09:13 +08:00
|
|
|
{
|
2018-11-11 04:14:50 +08:00
|
|
|
#ifdef ARCH_ECP5
|
|
|
|
// ECP5 global nets currently appear part-unrouted due to arch database limitations
|
|
|
|
// Don't touch them in the router
|
|
|
|
if (net_info->is_global)
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
if (net_info->driver.cell == nullptr)
|
|
|
|
return true;
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
return false;
|
|
|
|
}
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
void check()
|
2018-11-10 00:00:45 +08:00
|
|
|
{
|
2018-11-11 04:14:50 +08:00
|
|
|
std::unordered_set<arc_key, arc_key::Hash> valid_arcs;
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
for (auto &net_it : ctx->nets) {
|
2018-11-10 00:00:45 +08:00
|
|
|
NetInfo *net_info = net_it.second.get();
|
2018-11-11 04:14:50 +08:00
|
|
|
std::unordered_set<WireId> valid_wires_for_net;
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
if (skip_net(net_info))
|
2018-11-10 21:00:36 +08:00
|
|
|
continue;
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
#if 0
|
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log("[check] net: %s\n", ctx->nameOf(net_info));
|
2018-11-12 02:48:15 +08:00
|
|
|
#endif
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
|
|
|
log_assert(src_wire != WireId());
|
2018-06-23 21:58:24 +08:00
|
|
|
|
2018-07-22 08:16:03 +08:00
|
|
|
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
2021-02-10 22:31:16 +08:00
|
|
|
unsigned phys_idx = 0;
|
|
|
|
for (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) {
|
|
|
|
log_assert(dst_wire != WireId());
|
|
|
|
|
|
|
|
arc_key arc;
|
|
|
|
arc.net_info = net_info;
|
|
|
|
arc.user_idx = user_idx;
|
|
|
|
arc.phys_idx = phys_idx++;
|
|
|
|
valid_arcs.insert(arc);
|
2018-11-12 02:48:15 +08:00
|
|
|
#if 0
|
2021-02-10 22:31:16 +08:00
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log("[check] arc: %s %s\n", ctx->nameOfWire(src_wire), ctx->nameOfWire(dst_wire));
|
2018-11-12 02:48:15 +08:00
|
|
|
#endif
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2021-02-10 22:31:16 +08:00
|
|
|
for (WireId wire : arc_to_wires[arc]) {
|
2018-11-12 02:48:15 +08:00
|
|
|
#if 0
|
2021-02-10 22:31:16 +08:00
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log("[check] wire: %s\n", ctx->nameOfWire(wire));
|
2018-11-12 02:48:15 +08:00
|
|
|
#endif
|
2021-02-10 22:31:16 +08:00
|
|
|
valid_wires_for_net.insert(wire);
|
|
|
|
log_assert(wire_to_arcs[wire].count(arc));
|
|
|
|
log_assert(net_info->wires.count(wire));
|
|
|
|
}
|
2018-07-21 23:02:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
for (auto &it : net_info->wires) {
|
|
|
|
WireId w = it.first;
|
|
|
|
log_assert(valid_wires_for_net.count(w));
|
2018-07-21 23:02:53 +08:00
|
|
|
}
|
|
|
|
}
|
2018-06-19 18:49:40 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
for (auto &it : wire_to_arcs) {
|
|
|
|
for (auto &arc : it.second)
|
|
|
|
log_assert(valid_arcs.count(arc));
|
|
|
|
}
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
for (auto &it : arc_to_wires) {
|
|
|
|
log_assert(valid_arcs.count(it.first));
|
|
|
|
}
|
|
|
|
}
|
2018-06-13 23:52:18 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
void setup()
|
|
|
|
{
|
2018-11-12 02:48:15 +08:00
|
|
|
std::unordered_map<WireId, NetInfo *> src_to_net;
|
2018-11-11 19:04:02 +08:00
|
|
|
std::unordered_map<WireId, arc_key> dst_to_arc;
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
std::vector<IdString> net_names;
|
|
|
|
for (auto &net_it : ctx->nets)
|
|
|
|
net_names.push_back(net_it.first);
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
ctx->sorted_shuffle(net_names);
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-13 12:03:46 +08:00
|
|
|
for (IdString net_name : net_names) {
|
|
|
|
NetInfo *net_info = ctx->nets.at(net_name).get();
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
if (skip_net(net_info))
|
2018-11-10 21:00:36 +08:00
|
|
|
continue;
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
2018-06-13 22:52:21 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
if (src_wire == WireId())
|
2018-11-13 23:29:33 +08:00
|
|
|
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));
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-11 19:04:02 +08:00
|
|
|
if (src_to_net.count(src_wire))
|
2018-11-13 23:29:33 +08:00
|
|
|
log_error("Found two nets with same source wire %s: %s vs %s\n", ctx->nameOfWire(src_wire),
|
2018-11-11 19:04:02 +08:00
|
|
|
ctx->nameOf(net_info), ctx->nameOf(src_to_net.at(src_wire)));
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-11-11 19:04:02 +08:00
|
|
|
if (dst_to_arc.count(src_wire))
|
2018-11-12 02:48:15 +08:00
|
|
|
log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n",
|
2018-11-13 23:29:33 +08:00
|
|
|
ctx->nameOfWire(src_wire), ctx->nameOf(net_info),
|
2018-11-12 02:48:15 +08:00
|
|
|
ctx->nameOf(dst_to_arc.at(src_wire).net_info), dst_to_arc.at(src_wire).user_idx);
|
2018-06-10 00:19:20 +08:00
|
|
|
|
2018-07-22 08:16:03 +08:00
|
|
|
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
2021-02-10 22:31:16 +08:00
|
|
|
unsigned phys_idx = 0;
|
|
|
|
for (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) {
|
|
|
|
arc_key arc;
|
|
|
|
arc.net_info = net_info;
|
|
|
|
arc.user_idx = user_idx;
|
|
|
|
arc.phys_idx = phys_idx++;
|
|
|
|
|
|
|
|
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->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);
|
|
|
|
}
|
2018-06-23 21:58:24 +08:00
|
|
|
|
2021-02-10 22:31:16 +08:00
|
|
|
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->nameOfWire(dst_wire), ctx->nameOf(src_to_net.at(dst_wire)),
|
|
|
|
ctx->nameOf(net_info), user_idx);
|
2018-06-23 21:58:24 +08:00
|
|
|
|
2021-02-10 22:31:16 +08:00
|
|
|
dst_to_arc[dst_wire] = arc;
|
2018-08-04 23:23:46 +08:00
|
|
|
|
2021-02-10 22:31:16 +08:00
|
|
|
if (net_info->wires.count(dst_wire) == 0) {
|
2018-11-10 00:00:45 +08:00
|
|
|
arc_queue_insert(arc, src_wire, dst_wire);
|
2021-02-10 22:31:16 +08:00
|
|
|
continue;
|
2018-11-10 00:00:45 +08:00
|
|
|
}
|
2018-06-23 21:58:24 +08:00
|
|
|
|
2021-02-10 22:31:16 +08:00
|
|
|
WireId cursor = dst_wire;
|
2018-11-11 04:14:50 +08:00
|
|
|
wire_to_arcs[cursor].insert(arc);
|
|
|
|
arc_to_wires[arc].insert(cursor);
|
2021-02-10 22:31:16 +08:00
|
|
|
|
|
|
|
while (src_wire != cursor) {
|
|
|
|
auto it = net_info->wires.find(cursor);
|
|
|
|
if (it == net_info->wires.end()) {
|
|
|
|
arc_queue_insert(arc, src_wire, dst_wire);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
NPNR_ASSERT(it->second.pip != PipId());
|
|
|
|
cursor = ctx->getPipSrcWire(it->second.pip);
|
|
|
|
wire_to_arcs[cursor].insert(arc);
|
|
|
|
arc_to_wires[arc].insert(cursor);
|
|
|
|
}
|
2018-06-14 21:09:13 +08:00
|
|
|
}
|
2021-02-10 22:31:16 +08:00
|
|
|
// TODO: this matches the situation before supporting multiple cell->bel pins, but do we want to keep
|
|
|
|
// this invariant?
|
|
|
|
if (phys_idx == 0)
|
2021-03-24 07:53:42 +08:00
|
|
|
log_warning("No wires found for port %s on destination cell %s.\n",
|
|
|
|
ctx->nameOf(net_info->users[user_idx].port),
|
|
|
|
ctx->nameOf(net_info->users[user_idx].cell));
|
2018-06-10 00:19:20 +08:00
|
|
|
}
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-11 19:04:02 +08:00
|
|
|
src_to_net[src_wire] = net_info;
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
std::vector<WireId> unbind_wires;
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-07-21 23:02:53 +08:00
|
|
|
for (auto &it : net_info->wires)
|
2018-11-11 04:14:50 +08:00
|
|
|
if (it.second.strength < STRENGTH_LOCKED && wire_to_arcs.count(it.first) == 0)
|
2018-11-10 00:00:45 +08:00
|
|
|
unbind_wires.push_back(it.first);
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
for (auto it : unbind_wires)
|
2018-07-21 23:02:53 +08:00
|
|
|
ctx->unbindWire(it);
|
|
|
|
}
|
2018-11-10 00:00:45 +08:00
|
|
|
}
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
bool route_arc(const arc_key &arc, bool ripup)
|
|
|
|
{
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
NetInfo *net_info = arc.net_info;
|
|
|
|
int user_idx = arc.user_idx;
|
2018-06-15 01:13:14 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
2021-02-10 22:31:16 +08:00
|
|
|
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], arc.phys_idx);
|
2018-11-10 00:00:45 +08:00
|
|
|
ripup_flag = false;
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
if (ctx->debug) {
|
2018-11-13 23:29:33 +08:00
|
|
|
log("Routing arc %d on net %s (%d arcs total):\n", user_idx, ctx->nameOf(net_info),
|
2018-11-12 02:48:15 +08:00
|
|
|
int(net_info->users.size()));
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" source ... %s\n", ctx->nameOfWire(src_wire));
|
|
|
|
log(" sink ..... %s\n", ctx->nameOfWire(dst_wire));
|
2018-11-10 00:00:45 +08:00
|
|
|
}
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
// unbind wires that are currently used exclusively by this arc
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
std::unordered_set<WireId> old_arc_wires;
|
|
|
|
old_arc_wires.swap(arc_to_wires[arc]);
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
for (WireId wire : old_arc_wires) {
|
|
|
|
auto &arc_wires = wire_to_arcs.at(wire);
|
|
|
|
NPNR_ASSERT(arc_wires.count(arc));
|
|
|
|
arc_wires.erase(arc);
|
|
|
|
if (arc_wires.empty()) {
|
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" unbind %s\n", ctx->nameOfWire(wire));
|
2018-11-11 04:14:50 +08:00
|
|
|
ctx->unbindWire(wire);
|
|
|
|
}
|
2018-06-10 00:19:20 +08:00
|
|
|
}
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2020-11-12 19:08:13 +08:00
|
|
|
// special case
|
|
|
|
|
|
|
|
if (src_wire == dst_wire) {
|
|
|
|
NetInfo *bound = ctx->getBoundWireNet(src_wire);
|
|
|
|
if (bound != nullptr)
|
|
|
|
NPNR_ASSERT(bound == net_info);
|
|
|
|
else {
|
|
|
|
ctx->bindWire(src_wire, net_info, STRENGTH_WEAK);
|
|
|
|
}
|
|
|
|
arc_to_wires[arc].insert(src_wire);
|
|
|
|
wire_to_arcs[src_wire].insert(arc);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
// reset wire queue
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
if (!queue.empty()) {
|
|
|
|
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> new_queue;
|
|
|
|
queue.swap(new_queue);
|
2018-07-21 23:02:53 +08:00
|
|
|
}
|
2018-11-10 00:00:45 +08:00
|
|
|
visited.clear();
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
// A* main loop
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
int visitCnt = 0;
|
|
|
|
int maxVisitCnt = INT_MAX;
|
|
|
|
delay_t best_est = 0;
|
2018-11-10 05:39:39 +08:00
|
|
|
delay_t best_score = -1;
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
{
|
|
|
|
QueuedWire qw;
|
|
|
|
qw.wire = src_wire;
|
|
|
|
qw.pip = PipId();
|
|
|
|
qw.delay = ctx->getWireDelay(qw.wire).maxDelay();
|
|
|
|
qw.penalty = 0;
|
2018-11-10 05:39:39 +08:00
|
|
|
qw.bonus = 0;
|
2018-11-10 00:00:45 +08:00
|
|
|
if (cfg.useEstimate) {
|
|
|
|
qw.togo = ctx->estimateDelay(qw.wire, dst_wire);
|
|
|
|
best_est = qw.delay + qw.togo;
|
2018-07-21 23:02:53 +08:00
|
|
|
}
|
2018-11-10 00:00:45 +08:00
|
|
|
qw.randtag = ctx->rng();
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
queue.push(qw);
|
|
|
|
visited[qw.wire] = qw;
|
2018-07-21 17:52:41 +08:00
|
|
|
}
|
2018-06-15 01:13:14 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
while (visitCnt++ < maxVisitCnt && !queue.empty()) {
|
2018-11-10 00:00:45 +08:00
|
|
|
QueuedWire qw = queue.top();
|
|
|
|
queue.pop();
|
2018-06-15 01:13:14 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
for (auto pip : ctx->getPipsDownhill(qw.wire)) {
|
|
|
|
delay_t next_delay = qw.delay + ctx->getPipDelay(pip).maxDelay();
|
|
|
|
delay_t next_penalty = qw.penalty;
|
2018-11-10 05:39:39 +08:00
|
|
|
delay_t next_bonus = qw.bonus;
|
2018-07-21 17:52:41 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
WireId next_wire = ctx->getPipDstWire(pip);
|
|
|
|
next_delay += ctx->getWireDelay(next_wire).maxDelay();
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
WireId conflictWireWire = WireId(), conflictPipWire = WireId();
|
|
|
|
NetInfo *conflictWireNet = nullptr, *conflictPipNet = nullptr;
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-12 00:50:42 +08:00
|
|
|
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)
|
2018-11-10 00:00:45 +08:00
|
|
|
continue;
|
2018-11-12 00:50:42 +08:00
|
|
|
conflictWireWire = ctx->getConflictingWireWire(next_wire);
|
|
|
|
if (conflictWireWire == WireId()) {
|
|
|
|
conflictWireNet = ctx->getConflictingWireNet(next_wire);
|
|
|
|
if (conflictWireNet == nullptr)
|
|
|
|
continue;
|
2020-01-18 23:37:13 +08:00
|
|
|
else {
|
|
|
|
if (conflictWireNet->wires.count(next_wire) &&
|
|
|
|
conflictWireNet->wires.at(next_wire).strength > STRENGTH_STRONG)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
NetInfo *conflicting = ctx->getBoundWireNet(conflictWireWire);
|
|
|
|
if (conflicting != nullptr) {
|
|
|
|
if (conflicting->wires.count(conflictWireWire) &&
|
|
|
|
conflicting->wires.at(conflictWireWire).strength > STRENGTH_STRONG)
|
|
|
|
continue;
|
|
|
|
}
|
2018-11-12 00:50:42 +08:00
|
|
|
}
|
2018-11-12 00:28:41 +08:00
|
|
|
}
|
2018-06-15 01:13:14 +08:00
|
|
|
|
2018-11-12 00:50:42 +08:00
|
|
|
if (!ctx->checkPipAvail(pip)) {
|
|
|
|
if (!ripup)
|
2018-11-12 00:28:41 +08:00
|
|
|
continue;
|
2018-11-12 00:50:42 +08:00
|
|
|
conflictPipWire = ctx->getConflictingPipWire(pip);
|
|
|
|
if (conflictPipWire == WireId()) {
|
|
|
|
conflictPipNet = ctx->getConflictingPipNet(pip);
|
|
|
|
if (conflictPipNet == nullptr)
|
|
|
|
continue;
|
2020-01-18 23:37:13 +08:00
|
|
|
else {
|
|
|
|
if (conflictPipNet->wires.count(next_wire) &&
|
|
|
|
conflictPipNet->wires.at(next_wire).strength > STRENGTH_STRONG)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
NetInfo *conflicting = ctx->getBoundWireNet(conflictPipWire);
|
|
|
|
if (conflicting != nullptr) {
|
|
|
|
if (conflicting->wires.count(conflictPipWire) &&
|
|
|
|
conflicting->wires.at(conflictPipWire).strength > STRENGTH_STRONG)
|
|
|
|
continue;
|
|
|
|
}
|
2018-11-12 00:50:42 +08:00
|
|
|
}
|
2018-11-10 00:00:45 +08:00
|
|
|
}
|
2018-06-15 01:13:14 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (conflictWireNet != nullptr && conflictPipWire != WireId() &&
|
|
|
|
conflictWireNet->wires.count(conflictPipWire))
|
2018-11-12 00:50:42 +08:00
|
|
|
conflictPipWire = WireId();
|
2018-06-15 01:13:14 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (conflictPipNet != nullptr && conflictWireWire != WireId() &&
|
|
|
|
conflictPipNet->wires.count(conflictWireWire))
|
2018-11-12 00:50:42 +08:00
|
|
|
conflictWireWire = WireId();
|
2018-06-15 01:13:14 +08:00
|
|
|
|
2018-11-12 00:50:42 +08:00
|
|
|
if (conflictWireWire == conflictPipWire)
|
|
|
|
conflictWireWire = WireId();
|
2018-06-15 01:13:14 +08:00
|
|
|
|
2018-11-12 00:50:42 +08:00
|
|
|
if (conflictWireNet == conflictPipNet)
|
|
|
|
conflictWireNet = nullptr;
|
2018-06-15 01:13:14 +08:00
|
|
|
|
2018-11-12 00:50:42 +08:00
|
|
|
if (conflictWireWire != WireId()) {
|
|
|
|
auto scores_it = wireScores.find(conflictWireWire);
|
|
|
|
if (scores_it != wireScores.end())
|
|
|
|
next_penalty += scores_it->second * cfg.wireRipupPenalty;
|
|
|
|
next_penalty += cfg.wireRipupPenalty;
|
|
|
|
}
|
2018-06-15 01:13:14 +08:00
|
|
|
|
2018-11-12 00:50:42 +08:00
|
|
|
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;
|
|
|
|
}
|
2018-06-15 01:13:14 +08:00
|
|
|
|
2018-11-12 00:50:42 +08:00
|
|
|
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;
|
|
|
|
}
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-12 00:50:42 +08:00
|
|
|
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;
|
|
|
|
}
|
2018-11-10 00:00:45 +08:00
|
|
|
}
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-10 05:39:39 +08:00
|
|
|
delay_t next_score = next_delay + next_penalty;
|
|
|
|
NPNR_ASSERT(next_score >= 0);
|
2018-08-02 19:39:37 +08:00
|
|
|
|
2018-11-10 05:39:39 +08:00
|
|
|
if ((best_score >= 0) && (next_score - next_bonus - cfg.estimatePrecision > best_score))
|
|
|
|
continue;
|
2018-08-02 20:47:07 +08:00
|
|
|
|
2018-11-10 05:39:39 +08:00
|
|
|
auto old_visited_it = visited.find(next_wire);
|
|
|
|
if (old_visited_it != visited.end()) {
|
|
|
|
delay_t old_delay = old_visited_it->second.delay;
|
|
|
|
delay_t old_score = old_delay + old_visited_it->second.penalty;
|
|
|
|
NPNR_ASSERT(old_score >= 0);
|
2018-08-02 20:47:07 +08:00
|
|
|
|
2018-11-10 05:39:39 +08:00
|
|
|
if (next_score + ctx->getDelayEpsilon() >= old_score)
|
|
|
|
continue;
|
2018-08-02 20:47:07 +08:00
|
|
|
|
2018-11-10 05:39:39 +08:00
|
|
|
#if 0
|
2018-11-10 00:00:45 +08:00
|
|
|
if (ctx->debug)
|
2018-11-10 05:39:39 +08:00
|
|
|
log("Found better route to %s. Old vs new delay estimate: %.3f (%.3f) %.3f (%.3f)\n",
|
2018-11-13 23:29:33 +08:00
|
|
|
ctx->nameOfWire(next_wire),
|
2018-11-10 05:39:39 +08:00
|
|
|
ctx->getDelayNS(old_score),
|
|
|
|
ctx->getDelayNS(old_visited_it->second.delay),
|
|
|
|
ctx->getDelayNS(next_score),
|
2018-11-10 00:00:45 +08:00
|
|
|
ctx->getDelayNS(next_delay));
|
2018-09-30 00:36:08 +08:00
|
|
|
#endif
|
2018-11-10 00:00:45 +08:00
|
|
|
}
|
2018-08-02 20:47:07 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
QueuedWire next_qw;
|
|
|
|
next_qw.wire = next_wire;
|
|
|
|
next_qw.pip = pip;
|
|
|
|
next_qw.delay = next_delay;
|
|
|
|
next_qw.penalty = next_penalty;
|
2018-11-10 05:39:39 +08:00
|
|
|
next_qw.bonus = next_bonus;
|
2018-11-10 00:00:45 +08:00
|
|
|
if (cfg.useEstimate) {
|
|
|
|
next_qw.togo = ctx->estimateDelay(next_wire, dst_wire);
|
|
|
|
delay_t this_est = next_qw.delay + next_qw.togo;
|
2018-11-12 02:48:15 +08:00
|
|
|
if (this_est / 2 - cfg.estimatePrecision > best_est)
|
2018-11-10 00:00:45 +08:00
|
|
|
continue;
|
|
|
|
if (best_est > this_est)
|
|
|
|
best_est = this_est;
|
|
|
|
}
|
|
|
|
next_qw.randtag = ctx->rng();
|
2018-08-02 20:47:07 +08:00
|
|
|
|
2018-11-10 05:39:39 +08:00
|
|
|
#if 0
|
|
|
|
if (ctx->debug)
|
|
|
|
log("%s -> %s: %.3f (%.3f)\n",
|
2018-11-13 23:29:33 +08:00
|
|
|
ctx->nameOfWire(qw.wire),
|
|
|
|
ctx->nameOfWire(next_wire),
|
2018-11-10 05:39:39 +08:00
|
|
|
ctx->getDelayNS(next_score),
|
|
|
|
ctx->getDelayNS(next_delay));
|
|
|
|
#endif
|
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
visited[next_qw.wire] = next_qw;
|
|
|
|
queue.push(next_qw);
|
2018-08-02 20:47:07 +08:00
|
|
|
|
2018-11-10 05:39:39 +08:00
|
|
|
if (next_wire == dst_wire) {
|
2018-11-13 12:03:46 +08:00
|
|
|
maxVisitCnt = std::min(maxVisitCnt, 2 * visitCnt + (next_qw.penalty > 0 ? 100 : 0));
|
2018-11-10 05:39:39 +08:00
|
|
|
best_score = next_score - next_bonus;
|
|
|
|
}
|
2018-06-21 23:56:45 +08:00
|
|
|
}
|
2018-08-02 20:47:07 +08:00
|
|
|
}
|
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
if (ctx->debug)
|
|
|
|
log(" total number of visited nodes: %d\n", visitCnt);
|
2018-08-02 20:47:07 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
if (visited.count(dst_wire) == 0) {
|
|
|
|
if (ctx->debug)
|
|
|
|
log(" no route found for this arc\n");
|
|
|
|
return false;
|
|
|
|
}
|
2018-08-02 20:47:07 +08:00
|
|
|
|
2018-11-11 18:34:38 +08:00
|
|
|
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));
|
2018-11-13 12:03:46 +08:00
|
|
|
log(" arc budget: %12.2f\n", ctx->getDelayNS(net_info->users[user_idx].budget));
|
2018-08-01 23:05:30 +08:00
|
|
|
}
|
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
// bind resulting route (and maybe unroute other nets)
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
std::unordered_set<WireId> unassign_wires = arc_to_wires[arc];
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
WireId cursor = dst_wire;
|
2018-11-13 23:29:33 +08:00
|
|
|
delay_t accumulated_path_delay = 0;
|
2018-11-14 00:30:49 +08:00
|
|
|
delay_t last_path_delay_delta = 0;
|
2018-11-10 00:00:45 +08:00
|
|
|
while (1) {
|
2018-11-11 17:02:32 +08:00
|
|
|
auto pip = visited[cursor].pip;
|
2018-08-02 19:39:37 +08:00
|
|
|
|
2018-11-13 23:29:33 +08:00
|
|
|
if (ctx->debug) {
|
2018-11-14 00:30:49 +08:00
|
|
|
delay_t path_delay_delta = ctx->estimateDelay(cursor, dst_wire) - accumulated_path_delay;
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-14 00:30:49 +08:00
|
|
|
log(" node %s (%+.2f %+.2f)\n", ctx->nameOfWire(cursor), ctx->getDelayNS(path_delay_delta),
|
|
|
|
ctx->getDelayNS(path_delay_delta - last_path_delay_delta));
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-14 00:30:49 +08:00
|
|
|
last_path_delay_delta = path_delay_delta;
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-13 23:29:33 +08:00
|
|
|
if (pip != PipId())
|
|
|
|
accumulated_path_delay += ctx->getPipDelay(pip).maxDelay();
|
|
|
|
accumulated_path_delay += ctx->getWireDelay(cursor).maxDelay();
|
|
|
|
}
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (pip == PipId())
|
|
|
|
NPNR_ASSERT(cursor == src_wire);
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
if (!net_info->wires.count(cursor) || net_info->wires.at(cursor).pip != pip) {
|
|
|
|
if (!ctx->checkWireAvail(cursor)) {
|
2018-11-10 00:00:45 +08:00
|
|
|
ripup_wire(cursor);
|
2018-11-11 04:14:50 +08:00
|
|
|
NPNR_ASSERT(ctx->checkWireAvail(cursor));
|
|
|
|
}
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-12 00:28:41 +08:00
|
|
|
if (pip != PipId() && !ctx->checkPipAvail(pip)) {
|
|
|
|
ripup_pip(pip);
|
|
|
|
NPNR_ASSERT(ctx->checkPipAvail(pip));
|
2018-11-10 00:00:45 +08:00
|
|
|
}
|
2018-08-02 19:39:37 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
if (pip == PipId()) {
|
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" bind wire %s\n", ctx->nameOfWire(cursor));
|
2018-11-10 00:00:45 +08:00
|
|
|
ctx->bindWire(cursor, net_info, STRENGTH_WEAK);
|
2018-11-11 07:29:25 +08:00
|
|
|
} else {
|
2018-11-11 04:14:50 +08:00
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" bind pip %s\n", ctx->nameOfPip(pip));
|
2018-11-10 00:00:45 +08:00
|
|
|
ctx->bindPip(pip, net_info, STRENGTH_WEAK);
|
2018-11-11 04:14:50 +08:00
|
|
|
}
|
2018-11-10 00:00:45 +08:00
|
|
|
}
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
wire_to_arcs[cursor].insert(arc);
|
|
|
|
arc_to_wires[arc].insert(cursor);
|
2018-08-02 19:39:37 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
if (pip == PipId())
|
|
|
|
break;
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
cursor = ctx->getPipSrcWire(pip);
|
2018-08-01 23:05:30 +08:00
|
|
|
}
|
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
if (ripup_flag)
|
|
|
|
arcs_with_ripup++;
|
|
|
|
else
|
|
|
|
arcs_without_ripup++;
|
2018-08-02 19:39:37 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
return true;
|
2018-08-02 19:39:37 +08:00
|
|
|
}
|
2018-11-10 00:00:45 +08:00
|
|
|
};
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-07-21 23:02:53 +08:00
|
|
|
} // namespace
|
2018-06-18 01:43:07 +08:00
|
|
|
|
2018-07-21 23:02:53 +08:00
|
|
|
NEXTPNR_NAMESPACE_BEGIN
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2019-06-15 19:09:49 +08:00
|
|
|
Router1Cfg::Router1Cfg(Context *ctx)
|
2018-08-10 00:39:10 +08:00
|
|
|
{
|
2019-06-15 19:09:49 +08:00
|
|
|
maxIterCnt = ctx->setting<int>("router1/maxIterCnt", 200);
|
|
|
|
cleanupReroute = ctx->setting<bool>("router1/cleanupReroute", true);
|
|
|
|
fullCleanupReroute = ctx->setting<bool>("router1/fullCleanupReroute", true);
|
|
|
|
useEstimate = ctx->setting<bool>("router1/useEstimate", true);
|
2018-11-10 00:00:45 +08:00
|
|
|
|
|
|
|
wireRipupPenalty = ctx->getRipupDelayPenalty();
|
2018-11-12 02:48:15 +08:00
|
|
|
netRipupPenalty = 10 * ctx->getRipupDelayPenalty();
|
|
|
|
reuseBonus = wireRipupPenalty / 2;
|
2018-11-10 00:00:45 +08:00
|
|
|
|
|
|
|
estimatePrecision = 100 * ctx->getRipupDelayPenalty();
|
2018-08-10 00:39:10 +08:00
|
|
|
}
|
|
|
|
|
2018-08-02 19:58:23 +08:00
|
|
|
bool router1(Context *ctx, const Router1Cfg &cfg)
|
2018-07-21 23:02:53 +08:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
log_break();
|
|
|
|
log_info("Routing..\n");
|
2021-03-16 01:25:46 +08:00
|
|
|
ScopeLock<Context> lock(ctx);
|
2019-01-02 02:31:18 +08:00
|
|
|
auto rstart = std::chrono::high_resolution_clock::now();
|
2018-06-21 20:08:45 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
log_info("Setting up routing queue.\n");
|
2018-06-18 01:27:48 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
Router1 router(ctx, cfg);
|
|
|
|
router.setup();
|
2018-11-11 04:14:50 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
router.check();
|
|
|
|
#endif
|
2018-07-21 23:02:53 +08:00
|
|
|
|
2018-11-10 05:59:23 +08:00
|
|
|
log_info("Routing %d arcs.\n", int(router.arc_queue.size()));
|
2018-11-10 00:00:45 +08:00
|
|
|
|
|
|
|
int iter_cnt = 0;
|
|
|
|
int last_arcs_with_ripup = 0;
|
|
|
|
int last_arcs_without_ripup = 0;
|
2018-06-18 01:27:48 +08:00
|
|
|
|
2020-02-03 00:20:14 +08:00
|
|
|
log_info(" | (re-)routed arcs | delta | remaining| time spent |\n");
|
|
|
|
log_info(" IterCnt | w/ripup wo/ripup | w/r wo/r | arcs| batch(sec) total(sec)|\n");
|
2018-11-10 05:59:23 +08:00
|
|
|
|
2020-02-02 19:03:58 +08:00
|
|
|
auto prev_time = rstart;
|
2018-11-10 00:00:45 +08:00
|
|
|
while (!router.arc_queue.empty()) {
|
|
|
|
if (++iter_cnt % 1000 == 0) {
|
2020-02-02 19:03:58 +08:00
|
|
|
auto curr_time = std::chrono::high_resolution_clock::now();
|
2020-02-03 00:20:14 +08:00
|
|
|
log_info("%10d | %8d %10d | %4d %5d | %9d| %10.02f %10.02f|\n", iter_cnt, router.arcs_with_ripup,
|
2018-11-12 02:48:15 +08:00
|
|
|
router.arcs_without_ripup, router.arcs_with_ripup - last_arcs_with_ripup,
|
2020-02-02 19:03:58 +08:00
|
|
|
router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size()),
|
|
|
|
std::chrono::duration<float>(curr_time - prev_time).count(),
|
|
|
|
std::chrono::duration<float>(curr_time - rstart).count());
|
|
|
|
prev_time = curr_time;
|
2018-11-10 00:00:45 +08:00
|
|
|
last_arcs_with_ripup = router.arcs_with_ripup;
|
|
|
|
last_arcs_without_ripup = router.arcs_without_ripup;
|
2018-11-21 01:58:15 +08:00
|
|
|
ctx->yield();
|
2018-11-11 06:50:49 +08:00
|
|
|
#ifndef NDEBUG
|
2018-11-11 04:14:50 +08:00
|
|
|
router.check();
|
2018-11-11 06:50:49 +08:00
|
|
|
#endif
|
2018-11-10 00:00:45 +08:00
|
|
|
}
|
2018-06-18 01:27:48 +08:00
|
|
|
|
2018-11-11 17:02:32 +08:00
|
|
|
if (ctx->debug)
|
|
|
|
log("-- %d --\n", iter_cnt);
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
arc_key arc = router.arc_queue_pop();
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-10 00:00:45 +08:00
|
|
|
if (!router.route_arc(arc, true)) {
|
2018-11-13 23:29:33 +08:00
|
|
|
log_warning("Failed to find a route for arc %d of net %s.\n", arc.user_idx, ctx->nameOf(arc.net_info));
|
2018-06-23 21:16:24 +08:00
|
|
|
#ifndef NDEBUG
|
2018-11-11 07:29:25 +08:00
|
|
|
router.check();
|
2018-06-23 21:16:24 +08:00
|
|
|
ctx->check();
|
|
|
|
#endif
|
2018-06-21 23:56:45 +08:00
|
|
|
return false;
|
2018-06-14 21:09:13 +08:00
|
|
|
}
|
2018-06-21 23:56:45 +08:00
|
|
|
}
|
2019-01-02 02:31:18 +08:00
|
|
|
auto rend = std::chrono::high_resolution_clock::now();
|
2020-02-03 00:20:14 +08:00
|
|
|
log_info("%10d | %8d %10d | %4d %5d | %9d| %10.02f %10.02f|\n", iter_cnt, router.arcs_with_ripup,
|
2020-02-02 19:03:58 +08:00
|
|
|
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()),
|
|
|
|
std::chrono::duration<float>(rend - prev_time).count(),
|
|
|
|
std::chrono::duration<float>(rend - rstart).count());
|
|
|
|
log_info("Routing complete.\n");
|
2018-11-21 01:58:15 +08:00
|
|
|
ctx->yield();
|
2020-01-02 22:06:57 +08:00
|
|
|
log_info("Router1 time %.02fs\n", std::chrono::duration<float>(rend - rstart).count());
|
2018-06-21 20:08:45 +08:00
|
|
|
|
2018-06-23 21:16:24 +08:00
|
|
|
#ifndef NDEBUG
|
2018-11-11 06:50:49 +08:00
|
|
|
router.check();
|
2018-06-23 21:16:24 +08:00
|
|
|
ctx->check();
|
2018-11-11 06:50:49 +08:00
|
|
|
log_assert(ctx->checkRoutedDesign());
|
2018-06-23 21:16:24 +08:00
|
|
|
#endif
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-11 06:50:49 +08:00
|
|
|
log_info("Checksum: 0x%08x\n", ctx->checksum());
|
2018-11-22 01:13:53 +08:00
|
|
|
timing_analysis(ctx, true /* slack_histogram */, true /* print_fmax */, true /* print_path */,
|
|
|
|
true /* warn_on_failure */);
|
2018-06-18 01:27:48 +08:00
|
|
|
|
2018-06-21 23:56:45 +08:00
|
|
|
return true;
|
|
|
|
} catch (log_execution_error_exception) {
|
2018-06-23 21:16:24 +08:00
|
|
|
#ifndef NDEBUG
|
2021-03-02 01:41:29 +08:00
|
|
|
ctx->lock();
|
2018-06-23 21:16:24 +08:00
|
|
|
ctx->check();
|
2018-07-26 22:45:57 +08:00
|
|
|
ctx->unlock();
|
2021-03-02 01:41:29 +08:00
|
|
|
#endif
|
2018-06-21 23:56:45 +08:00
|
|
|
return false;
|
|
|
|
}
|
2018-06-10 00:19:20 +08:00
|
|
|
}
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-11 04:14:50 +08:00
|
|
|
bool Context::checkRoutedDesign() const
|
|
|
|
{
|
2018-11-12 02:48:15 +08:00
|
|
|
const Context *ctx = getCtx();
|
2018-06-19 18:49:40 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
for (auto &net_it : ctx->nets) {
|
|
|
|
NetInfo *net_info = net_it.second.get();
|
2018-06-18 01:27:48 +08:00
|
|
|
|
2018-11-12 19:23:31 +08:00
|
|
|
#ifdef ARCH_ECP5
|
|
|
|
if (net_info->is_global)
|
|
|
|
continue;
|
|
|
|
#endif
|
2018-08-02 19:58:23 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log("checking net %s\n", ctx->nameOf(net_info));
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (net_info->users.empty()) {
|
|
|
|
if (ctx->debug)
|
|
|
|
log(" net without sinks\n");
|
|
|
|
log_assert(net_info->wires.empty());
|
|
|
|
continue;
|
|
|
|
}
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
bool found_unrouted = false;
|
|
|
|
bool found_loop = false;
|
|
|
|
bool found_stub = false;
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
struct ExtraWireInfo
|
|
|
|
{
|
|
|
|
int order_num = 0;
|
|
|
|
std::unordered_set<WireId> children;
|
|
|
|
};
|
2018-06-18 01:27:48 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
std::unordered_map<WireId, ExtraWireInfo> db;
|
2018-06-14 21:09:13 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
for (auto &it : net_info->wires) {
|
|
|
|
WireId w = it.first;
|
|
|
|
PipId p = it.second.pip;
|
2018-06-21 23:56:45 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (p != PipId()) {
|
|
|
|
log_assert(ctx->getPipDstWire(p) == w);
|
|
|
|
db[ctx->getPipSrcWire(p)].children.insert(w);
|
2018-07-22 03:00:42 +08:00
|
|
|
}
|
2018-11-12 02:48:15 +08:00
|
|
|
}
|
2018-06-16 21:23:04 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
2018-11-22 01:23:20 +08:00
|
|
|
if (src_wire == WireId()) {
|
|
|
|
log_assert(net_info->driver.cell == nullptr);
|
|
|
|
if (ctx->debug)
|
|
|
|
log(" undriven and unrouted\n");
|
|
|
|
continue;
|
|
|
|
}
|
2018-06-21 23:56:45 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (net_info->wires.count(src_wire) == 0) {
|
|
|
|
if (ctx->debug)
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" source (%s) not bound to net\n", ctx->nameOfWire(src_wire));
|
2018-11-12 02:48:15 +08:00
|
|
|
found_unrouted = true;
|
|
|
|
}
|
2018-06-21 23:56:45 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
std::unordered_map<WireId, int> dest_wires;
|
|
|
|
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
2021-02-10 22:31:16 +08:00
|
|
|
for (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) {
|
|
|
|
log_assert(dst_wire != WireId());
|
|
|
|
dest_wires[dst_wire] = user_idx;
|
2018-06-21 23:56:45 +08:00
|
|
|
|
2021-02-10 22:31:16 +08:00
|
|
|
if (net_info->wires.count(dst_wire) == 0) {
|
|
|
|
if (ctx->debug)
|
|
|
|
log(" sink %d (%s) not bound to net\n", user_idx, ctx->nameOfWire(dst_wire));
|
|
|
|
found_unrouted = true;
|
|
|
|
}
|
2018-11-11 04:14:50 +08:00
|
|
|
}
|
2018-11-12 02:48:15 +08:00
|
|
|
}
|
2018-06-21 20:08:45 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
std::function<void(WireId, int)> setOrderNum;
|
|
|
|
std::unordered_set<WireId> logged_wires;
|
2018-06-21 20:08:45 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
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;
|
2018-11-11 04:14:50 +08:00
|
|
|
}
|
2018-11-12 02:48:15 +08:00
|
|
|
db_entry.order_num = num;
|
|
|
|
for (WireId child : db_entry.children) {
|
|
|
|
if (ctx->debug) {
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" %*s-> %s\n", 2 * num, "", ctx->nameOfWire(child));
|
2018-11-12 02:48:15 +08:00
|
|
|
logged_wires.insert(child);
|
2018-06-21 23:56:45 +08:00
|
|
|
}
|
2018-11-12 02:48:15 +08:00
|
|
|
setOrderNum(child, num + 1);
|
2018-06-21 23:56:45 +08:00
|
|
|
}
|
2018-11-12 02:48:15 +08:00
|
|
|
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;
|
2018-11-11 04:14:50 +08:00
|
|
|
}
|
|
|
|
}
|
2018-11-12 02:48:15 +08:00
|
|
|
};
|
2018-06-21 23:56:45 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (ctx->debug) {
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" driver: %s\n", ctx->nameOfWire(src_wire));
|
2018-11-12 02:48:15 +08:00
|
|
|
logged_wires.insert(src_wire);
|
|
|
|
}
|
|
|
|
setOrderNum(src_wire, 1);
|
2018-07-17 23:27:50 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
std::unordered_set<WireId> dangling_wires;
|
2018-08-01 23:05:30 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
for (auto &it : db) {
|
|
|
|
auto &db_entry = it.second;
|
|
|
|
if (db_entry.order_num == 0)
|
|
|
|
dangling_wires.insert(it.first);
|
2018-06-21 23:56:45 +08:00
|
|
|
}
|
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (ctx->debug) {
|
|
|
|
if (dangling_wires.empty()) {
|
|
|
|
log(" no dangling wires.\n");
|
|
|
|
} else {
|
|
|
|
std::unordered_set<WireId> root_wires = dangling_wires;
|
|
|
|
|
|
|
|
for (WireId w : dangling_wires) {
|
|
|
|
for (WireId c : db[w].children)
|
|
|
|
root_wires.erase(c);
|
|
|
|
}
|
2018-06-22 02:41:20 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
for (WireId w : root_wires) {
|
2018-11-13 23:29:33 +08:00
|
|
|
log(" dangling wire: %s\n", ctx->nameOfWire(w));
|
2018-11-12 02:48:15 +08:00
|
|
|
logged_wires.insert(w);
|
|
|
|
setOrderNum(w, 1);
|
|
|
|
}
|
2018-06-22 02:41:20 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
for (WireId w : dangling_wires) {
|
|
|
|
if (logged_wires.count(w) == 0)
|
2018-11-16 21:25:51 +08:00
|
|
|
log(" loop: %s -> %s\n", ctx->nameOfWire(ctx->getPipSrcWire(net_info->wires.at(w).pip)),
|
2018-11-13 23:29:33 +08:00
|
|
|
ctx->nameOfWire(w));
|
2018-07-22 08:16:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
bool fail = false;
|
2018-07-21 23:54:47 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (found_unrouted) {
|
|
|
|
if (ctx->debug)
|
|
|
|
log("check failed: found unrouted arcs\n");
|
|
|
|
fail = true;
|
|
|
|
}
|
2018-07-21 23:54:47 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (found_loop) {
|
|
|
|
if (ctx->debug)
|
|
|
|
log("check failed: found loops\n");
|
|
|
|
fail = true;
|
2018-07-21 23:54:47 +08:00
|
|
|
}
|
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (found_stub) {
|
|
|
|
if (ctx->debug)
|
|
|
|
log("check failed: found stubs\n");
|
|
|
|
fail = true;
|
|
|
|
}
|
2018-11-11 06:50:49 +08:00
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (!dangling_wires.empty()) {
|
|
|
|
if (ctx->debug)
|
|
|
|
log("check failed: found dangling wires\n");
|
|
|
|
fail = true;
|
2018-11-11 04:14:50 +08:00
|
|
|
}
|
|
|
|
|
2018-11-12 02:48:15 +08:00
|
|
|
if (fail)
|
|
|
|
return false;
|
2018-06-21 23:56:45 +08:00
|
|
|
}
|
2018-11-12 02:48:15 +08:00
|
|
|
|
|
|
|
return true;
|
2018-06-10 00:19:20 +08:00
|
|
|
}
|
2018-06-12 20:24:59 +08:00
|
|
|
|
2018-08-04 19:41:42 +08:00
|
|
|
bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay,
|
2018-08-04 17:57:34 +08:00
|
|
|
std::unordered_map<WireId, PipId> *route, bool useEstimate)
|
2018-06-20 20:04:10 +08:00
|
|
|
{
|
2018-11-10 00:00:45 +08:00
|
|
|
// FIXME
|
|
|
|
return false;
|
2018-06-20 20:04:10 +08:00
|
|
|
}
|
|
|
|
|
2018-06-12 20:24:59 +08:00
|
|
|
NEXTPNR_NAMESPACE_END
|