Merge branch 'router_improve' of http://github.com/YosysHQ/nextpnr into xc7-router_improve
This commit is contained in:
commit
97f1901fcf
@ -53,6 +53,30 @@ void IdString::initialize_add(const BaseCtx *ctx, const char *s, int idx)
|
||||
ctx->idstring_idx_to_str->push_back(&insert_rc.first->first);
|
||||
}
|
||||
|
||||
const char *BaseCtx::nameOfBel(BelId bel) const
|
||||
{
|
||||
const Context *ctx = getCtx();
|
||||
return ctx->getBelName(bel).c_str(ctx);
|
||||
}
|
||||
|
||||
const char *BaseCtx::nameOfWire(WireId wire) const
|
||||
{
|
||||
const Context *ctx = getCtx();
|
||||
return ctx->getWireName(wire).c_str(ctx);
|
||||
}
|
||||
|
||||
const char *BaseCtx::nameOfPip(PipId pip) const
|
||||
{
|
||||
const Context *ctx = getCtx();
|
||||
return ctx->getPipName(pip).c_str(ctx);
|
||||
}
|
||||
|
||||
const char *BaseCtx::nameOfGroup(GroupId group) const
|
||||
{
|
||||
const Context *ctx = getCtx();
|
||||
return ctx->getGroupName(group).c_str(ctx);
|
||||
}
|
||||
|
||||
WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const
|
||||
{
|
||||
if (net_info->driver.cell == nullptr)
|
||||
|
@ -487,13 +487,23 @@ struct BaseCtx
|
||||
|
||||
const Context *getCtx() const { return reinterpret_cast<const Context *>(this); }
|
||||
|
||||
template <typename T> const char *nameOf(const T *obj)
|
||||
const char *nameOf(IdString name) const
|
||||
{
|
||||
return name.c_str(this);
|
||||
}
|
||||
|
||||
template <typename T> const char *nameOf(const T *obj) const
|
||||
{
|
||||
if (obj == nullptr)
|
||||
return "";
|
||||
return obj->name.c_str(getCtx());
|
||||
return obj->name.c_str(this);
|
||||
}
|
||||
|
||||
const char *nameOfBel(BelId bel) const;
|
||||
const char *nameOfWire(WireId wire) const;
|
||||
const char *nameOfPip(PipId pip) const;
|
||||
const char *nameOfGroup(GroupId group) const;
|
||||
|
||||
// --------------------------------------------------------------
|
||||
|
||||
bool allUiReload = true;
|
||||
|
@ -33,15 +33,14 @@ struct arc_key
|
||||
NetInfo *net_info;
|
||||
int user_idx;
|
||||
|
||||
bool operator==(const arc_key &other) const {
|
||||
return (net_info == other.net_info) && (user_idx == other.user_idx);
|
||||
}
|
||||
bool operator==(const arc_key &other) const { return (net_info == other.net_info) && (user_idx == other.user_idx); }
|
||||
bool operator<(const arc_key &other) const { return net_info == other.net_info ? user_idx < other.user_idx : net_info->name < other.net_info->name; }
|
||||
|
||||
struct Hash
|
||||
{
|
||||
std::size_t operator()(const arc_key &arg) const noexcept
|
||||
{
|
||||
std::size_t seed = std::hash<NetInfo*>()(arg.net_info);
|
||||
std::size_t seed = std::hash<NetInfo *>()(arg.net_info);
|
||||
seed ^= std::hash<int>()(arg.user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
return seed;
|
||||
}
|
||||
@ -52,12 +51,15 @@ struct arc_entry
|
||||
{
|
||||
arc_key arc;
|
||||
delay_t pri;
|
||||
int randtag = 0;
|
||||
|
||||
struct Greater
|
||||
struct Less
|
||||
{
|
||||
bool operator()(const arc_entry &lhs, const arc_entry &rhs) const noexcept
|
||||
{
|
||||
return lhs.pri > rhs.pri;
|
||||
if (lhs.pri != rhs.pri)
|
||||
return lhs.pri < rhs.pri;
|
||||
return lhs.randtag < rhs.randtag;
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -90,7 +92,7 @@ struct Router1
|
||||
Context *ctx;
|
||||
const Router1Cfg &cfg;
|
||||
|
||||
std::priority_queue<arc_entry, std::vector<arc_entry>, arc_entry::Greater> arc_queue;
|
||||
std::priority_queue<arc_entry, std::vector<arc_entry>, arc_entry::Less> arc_queue;
|
||||
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;
|
||||
std::unordered_set<arc_key, arc_key::Hash> queued_arcs;
|
||||
@ -99,13 +101,13 @@ struct Router1
|
||||
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue;
|
||||
|
||||
std::unordered_map<WireId, int> wireScores;
|
||||
std::unordered_map<NetInfo*, int> netScores;
|
||||
std::unordered_map<NetInfo *, int> netScores;
|
||||
|
||||
int arcs_with_ripup = 0;
|
||||
int arcs_without_ripup = 0;
|
||||
bool ripup_flag;
|
||||
|
||||
Router1(Context *ctx, const Router1Cfg &cfg) : ctx(ctx), cfg(cfg) { }
|
||||
Router1(Context *ctx, const Router1Cfg &cfg) : ctx(ctx), cfg(cfg) {}
|
||||
|
||||
void arc_queue_insert(const arc_key &arc, WireId src_wire, WireId dst_wire)
|
||||
{
|
||||
@ -117,6 +119,13 @@ struct Router1
|
||||
arc_entry entry;
|
||||
entry.arc = arc;
|
||||
entry.pri = pri;
|
||||
entry.randtag = ctx->rng();
|
||||
|
||||
#if 0
|
||||
if (ctx->debug)
|
||||
log("[arc_queue_insert] %s (%d) %s %s [%d %d]\n", ctx->nameOf(entry.arc.net_info), entry.arc.user_idx,
|
||||
ctx->nameOfWire(src_wire), ctx->nameOfWire(dst_wire), (int)entry.pri, entry.randtag);
|
||||
#endif
|
||||
|
||||
arc_queue.push(entry);
|
||||
queued_arcs.insert(arc);
|
||||
@ -139,6 +148,13 @@ struct Router1
|
||||
arc_key arc_queue_pop()
|
||||
{
|
||||
arc_entry entry = arc_queue.top();
|
||||
|
||||
#if 0
|
||||
if (ctx->debug)
|
||||
log("[arc_queue_pop] %s (%d) [%d %d]\n", ctx->nameOf(entry.arc.net_info), entry.arc.user_idx,
|
||||
(int)entry.pri, entry.randtag);
|
||||
#endif
|
||||
|
||||
arc_queue.pop();
|
||||
queued_arcs.erase(entry.arc);
|
||||
return entry.arc;
|
||||
@ -147,22 +163,31 @@ struct Router1
|
||||
void ripup_net(NetInfo *net)
|
||||
{
|
||||
if (ctx->debug)
|
||||
log(" ripup net %s\n", net->name.c_str(ctx));
|
||||
log(" ripup net %s\n", ctx->nameOf(net));
|
||||
|
||||
netScores[net]++;
|
||||
|
||||
auto net_wires_copy = net->wires;
|
||||
for (auto &it : net_wires_copy) {
|
||||
WireId w = it.first;
|
||||
std::vector<WireId> wires;
|
||||
for (auto &it : net->wires)
|
||||
wires.push_back(it.first);
|
||||
|
||||
ctx->sorted_shuffle(wires);
|
||||
|
||||
for (WireId w : wires) {
|
||||
std::vector<arc_key> arcs;
|
||||
for (auto &it : wire_to_arcs[w]) {
|
||||
arc_to_wires[it].erase(w);
|
||||
arc_queue_insert(it);
|
||||
arcs.push_back(it);
|
||||
}
|
||||
wire_to_arcs[w].clear();
|
||||
|
||||
ctx->sorted_shuffle(arcs);
|
||||
|
||||
for (auto &it : arcs)
|
||||
arc_queue_insert(it);
|
||||
|
||||
if (ctx->debug)
|
||||
log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx));
|
||||
log(" unbind wire %s\n", ctx->nameOfWire(w));
|
||||
|
||||
ctx->unbindWire(w);
|
||||
wireScores[w]++;
|
||||
@ -174,7 +199,7 @@ struct Router1
|
||||
void ripup_wire(WireId wire, int extra_indent = 0)
|
||||
{
|
||||
if (ctx->debug)
|
||||
log(" ripup wire %s\n", ctx->getWireName(wire).c_str(ctx));
|
||||
log(" ripup wire %s\n", ctx->nameOfWire(wire));
|
||||
|
||||
WireId w = ctx->getConflictingWireWire(wire);
|
||||
|
||||
@ -183,14 +208,20 @@ struct Router1
|
||||
if (n != nullptr)
|
||||
ripup_net(n);
|
||||
} else {
|
||||
std::vector<arc_key> arcs;
|
||||
for (auto &it : wire_to_arcs[w]) {
|
||||
arc_to_wires[it].erase(w);
|
||||
arc_queue_insert(it);
|
||||
arcs.push_back(it);
|
||||
}
|
||||
wire_to_arcs[w].clear();
|
||||
|
||||
ctx->sorted_shuffle(arcs);
|
||||
|
||||
for (auto &it : arcs)
|
||||
arc_queue_insert(it);
|
||||
|
||||
if (ctx->debug)
|
||||
log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx));
|
||||
log(" unbind wire %s\n", ctx->nameOfWire(w));
|
||||
|
||||
ctx->unbindWire(w);
|
||||
wireScores[w]++;
|
||||
@ -202,7 +233,7 @@ struct Router1
|
||||
void ripup_pip(PipId pip)
|
||||
{
|
||||
if (ctx->debug)
|
||||
log(" ripup pip %s\n", ctx->getPipName(pip).c_str(ctx));
|
||||
log(" ripup pip %s\n", ctx->nameOfPip(pip));
|
||||
|
||||
WireId w = ctx->getConflictingPipWire(pip);
|
||||
|
||||
@ -211,14 +242,20 @@ struct Router1
|
||||
if (n != nullptr)
|
||||
ripup_net(n);
|
||||
} else {
|
||||
std::vector<arc_key> arcs;
|
||||
for (auto &it : wire_to_arcs[w]) {
|
||||
arc_to_wires[it].erase(w);
|
||||
arc_queue_insert(it);
|
||||
arcs.push_back(it);
|
||||
}
|
||||
wire_to_arcs[w].clear();
|
||||
|
||||
ctx->sorted_shuffle(arcs);
|
||||
|
||||
for (auto &it : arcs)
|
||||
arc_queue_insert(it);
|
||||
|
||||
if (ctx->debug)
|
||||
log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx));
|
||||
log(" unbind wire %s\n", ctx->nameOfWire(w));
|
||||
|
||||
ctx->unbindWire(w);
|
||||
wireScores[w]++;
|
||||
@ -245,15 +282,17 @@ struct Router1
|
||||
{
|
||||
std::unordered_set<arc_key, arc_key::Hash> valid_arcs;
|
||||
|
||||
for (auto &net_it : ctx->nets)
|
||||
{
|
||||
for (auto &net_it : ctx->nets) {
|
||||
NetInfo *net_info = net_it.second.get();
|
||||
std::unordered_set<WireId> valid_wires_for_net;
|
||||
|
||||
if (skip_net(net_info))
|
||||
continue;
|
||||
|
||||
// log("[check] net: %s\n", net_info->name.c_str(ctx));
|
||||
#if 0
|
||||
if (ctx->debug)
|
||||
log("[check] net: %s\n", ctx->nameOf(net_info));
|
||||
#endif
|
||||
|
||||
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
||||
log_assert(src_wire != WireId());
|
||||
@ -267,10 +306,16 @@ struct Router1
|
||||
arc.user_idx = user_idx;
|
||||
|
||||
valid_arcs.insert(arc);
|
||||
// log("[check] arc: %s %s\n", ctx->getWireName(src_wire).c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx));
|
||||
#if 0
|
||||
if (ctx->debug)
|
||||
log("[check] arc: %s %s\n", ctx->nameOfWire(src_wire), ctx->nameOfWire(dst_wire));
|
||||
#endif
|
||||
|
||||
for (WireId wire : arc_to_wires[arc]) {
|
||||
// log("[check] wire: %s\n", ctx->getWireName(wire).c_str(ctx));
|
||||
#if 0
|
||||
if (ctx->debug)
|
||||
log("[check] wire: %s\n", ctx->nameOfWire(wire));
|
||||
#endif
|
||||
valid_wires_for_net.insert(wire);
|
||||
log_assert(wire_to_arcs[wire].count(arc));
|
||||
log_assert(net_info->wires.count(wire));
|
||||
@ -295,12 +340,17 @@ struct Router1
|
||||
|
||||
void setup()
|
||||
{
|
||||
std::unordered_map<WireId, NetInfo*> src_to_net;
|
||||
std::unordered_map<WireId, NetInfo *> src_to_net;
|
||||
std::unordered_map<WireId, arc_key> dst_to_arc;
|
||||
|
||||
std::vector<IdString> net_names;
|
||||
for (auto &net_it : ctx->nets)
|
||||
{
|
||||
NetInfo *net_info = net_it.second.get();
|
||||
net_names.push_back(net_it.first);
|
||||
|
||||
ctx->sorted_shuffle(net_names);
|
||||
|
||||
for (IdString net_name : net_names) {
|
||||
NetInfo *net_info = ctx->nets.at(net_name).get();
|
||||
|
||||
if (skip_net(net_info))
|
||||
continue;
|
||||
@ -308,34 +358,38 @@ struct Router1
|
||||
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
||||
|
||||
if (src_wire == WireId())
|
||||
log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx),
|
||||
net_info->driver.cell->name.c_str(ctx));
|
||||
log_error("No wire found for port %s on source cell %s.\n", ctx->nameOf(net_info->driver.port),
|
||||
ctx->nameOf(net_info->driver.cell));
|
||||
|
||||
if (src_to_net.count(src_wire))
|
||||
log_error("Found two nets with same source wire %s: %s vs %s\n", ctx->getWireName(src_wire).c_str(ctx),
|
||||
log_error("Found two nets with same source wire %s: %s vs %s\n", ctx->nameOfWire(src_wire),
|
||||
ctx->nameOf(net_info), ctx->nameOf(src_to_net.at(src_wire)));
|
||||
|
||||
if (dst_to_arc.count(src_wire))
|
||||
log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n", ctx->getWireName(src_wire).c_str(ctx),
|
||||
ctx->nameOf(net_info), ctx->nameOf(dst_to_arc.at(src_wire).net_info), dst_to_arc.at(src_wire).user_idx);
|
||||
log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n",
|
||||
ctx->nameOfWire(src_wire), ctx->nameOf(net_info),
|
||||
ctx->nameOf(dst_to_arc.at(src_wire).net_info), dst_to_arc.at(src_wire).user_idx);
|
||||
|
||||
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
||||
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]);
|
||||
|
||||
if (dst_wire == WireId())
|
||||
log_error("No wire found for port %s on destination cell %s.\n", net_info->users[user_idx].port.c_str(ctx),
|
||||
net_info->users[user_idx].cell->name.c_str(ctx));
|
||||
log_error("No wire 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));
|
||||
|
||||
if (dst_to_arc.count(dst_wire)) {
|
||||
if (dst_to_arc.at(dst_wire).net_info == net_info)
|
||||
continue;
|
||||
log_error("Found two arcs with same sink wire %s: %s (%d) vs %s (%d)\n", ctx->getWireName(dst_wire).c_str(ctx),
|
||||
ctx->nameOf(net_info), user_idx, ctx->nameOf(dst_to_arc.at(dst_wire).net_info), dst_to_arc.at(dst_wire).user_idx);
|
||||
log_error("Found two arcs with same sink wire %s: %s (%d) vs %s (%d)\n",
|
||||
ctx->nameOfWire(dst_wire), ctx->nameOf(net_info), user_idx,
|
||||
ctx->nameOf(dst_to_arc.at(dst_wire).net_info), dst_to_arc.at(dst_wire).user_idx);
|
||||
}
|
||||
|
||||
if (src_to_net.count(dst_wire))
|
||||
log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n", ctx->getWireName(dst_wire).c_str(ctx),
|
||||
ctx->nameOf(src_to_net.at(dst_wire)), ctx->nameOf(net_info), user_idx);
|
||||
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);
|
||||
|
||||
arc_key arc;
|
||||
arc.net_info = net_info;
|
||||
@ -390,9 +444,10 @@ struct Router1
|
||||
ripup_flag = false;
|
||||
|
||||
if (ctx->debug) {
|
||||
log("Routing arc %d on net %s (%d arcs total):\n", user_idx, net_info->name.c_str(ctx), int(net_info->users.size()));
|
||||
log(" source ... %s\n", ctx->getWireName(src_wire).c_str(ctx));
|
||||
log(" sink ..... %s\n", ctx->getWireName(dst_wire).c_str(ctx));
|
||||
log("Routing arc %d on net %s (%d arcs total):\n", user_idx, ctx->nameOf(net_info),
|
||||
int(net_info->users.size()));
|
||||
log(" source ... %s\n", ctx->nameOfWire(src_wire));
|
||||
log(" sink ..... %s\n", ctx->nameOfWire(dst_wire));
|
||||
}
|
||||
|
||||
// unbind wires that are currently used exclusively by this arc
|
||||
@ -406,7 +461,7 @@ struct Router1
|
||||
arc_wires.erase(arc);
|
||||
if (arc_wires.empty()) {
|
||||
if (ctx->debug)
|
||||
log(" unbind %s\n", ctx->getWireName(wire).c_str(ctx));
|
||||
log(" unbind %s\n", ctx->nameOfWire(wire));
|
||||
ctx->unbindWire(wire);
|
||||
}
|
||||
}
|
||||
@ -443,8 +498,7 @@ struct Router1
|
||||
visited[qw.wire] = qw;
|
||||
}
|
||||
|
||||
while (visitCnt++ < maxVisitCnt && !queue.empty())
|
||||
{
|
||||
while (visitCnt++ < maxVisitCnt && !queue.empty()) {
|
||||
QueuedWire qw = queue.top();
|
||||
queue.pop();
|
||||
|
||||
@ -484,10 +538,12 @@ struct Router1
|
||||
}
|
||||
}
|
||||
|
||||
if (conflictWireNet != nullptr && conflictPipWire != WireId() && conflictWireNet->wires.count(conflictPipWire))
|
||||
if (conflictWireNet != nullptr && conflictPipWire != WireId() &&
|
||||
conflictWireNet->wires.count(conflictPipWire))
|
||||
conflictPipWire = WireId();
|
||||
|
||||
if (conflictPipNet != nullptr && conflictWireWire != WireId() && conflictPipNet->wires.count(conflictWireWire))
|
||||
if (conflictPipNet != nullptr && conflictWireWire != WireId() &&
|
||||
conflictPipNet->wires.count(conflictWireWire))
|
||||
conflictWireWire = WireId();
|
||||
|
||||
if (conflictWireWire == conflictPipWire)
|
||||
@ -545,7 +601,7 @@ struct Router1
|
||||
#if 0
|
||||
if (ctx->debug)
|
||||
log("Found better route to %s. Old vs new delay estimate: %.3f (%.3f) %.3f (%.3f)\n",
|
||||
ctx->getWireName(next_wire).c_str(ctx),
|
||||
ctx->nameOfWire(next_wire),
|
||||
ctx->getDelayNS(old_score),
|
||||
ctx->getDelayNS(old_visited_it->second.delay),
|
||||
ctx->getDelayNS(next_score),
|
||||
@ -562,7 +618,7 @@ struct Router1
|
||||
if (cfg.useEstimate) {
|
||||
next_qw.togo = ctx->estimateDelay(next_wire, dst_wire);
|
||||
delay_t this_est = next_qw.delay + next_qw.togo;
|
||||
if (this_est/2 - cfg.estimatePrecision > best_est)
|
||||
if (this_est / 2 - cfg.estimatePrecision > best_est)
|
||||
continue;
|
||||
if (best_est > this_est)
|
||||
best_est = this_est;
|
||||
@ -572,8 +628,8 @@ struct Router1
|
||||
#if 0
|
||||
if (ctx->debug)
|
||||
log("%s -> %s: %.3f (%.3f)\n",
|
||||
ctx->getWireName(qw.wire).c_str(ctx),
|
||||
ctx->getWireName(next_wire).c_str(ctx),
|
||||
ctx->nameOfWire(qw.wire),
|
||||
ctx->nameOfWire(next_wire),
|
||||
ctx->getDelayNS(next_score),
|
||||
ctx->getDelayNS(next_delay));
|
||||
#endif
|
||||
@ -582,8 +638,7 @@ struct Router1
|
||||
queue.push(next_qw);
|
||||
|
||||
if (next_wire == dst_wire) {
|
||||
if (maxVisitCnt == INT_MAX)
|
||||
maxVisitCnt = 2*visitCnt;
|
||||
maxVisitCnt = std::min(maxVisitCnt, 2 * visitCnt + (next_qw.penalty > 0 ? 100 : 0));
|
||||
best_score = next_score - next_bonus;
|
||||
}
|
||||
}
|
||||
@ -602,6 +657,7 @@ struct Router1
|
||||
log(" final route delay: %8.2f\n", ctx->getDelayNS(visited[dst_wire].delay));
|
||||
log(" final route penalty: %8.2f\n", ctx->getDelayNS(visited[dst_wire].penalty));
|
||||
log(" final route bonus: %8.2f\n", ctx->getDelayNS(visited[dst_wire].bonus));
|
||||
log(" arc budget: %12.2f\n", ctx->getDelayNS(net_info->users[user_idx].budget));
|
||||
}
|
||||
|
||||
// bind resulting route (and maybe unroute other nets)
|
||||
@ -609,14 +665,26 @@ struct Router1
|
||||
std::unordered_set<WireId> unassign_wires = arc_to_wires[arc];
|
||||
|
||||
WireId cursor = dst_wire;
|
||||
delay_t accumulated_path_delay = 0;
|
||||
delay_t last_path_delay_delta = 0;
|
||||
while (1) {
|
||||
auto pip = visited[cursor].pip;
|
||||
|
||||
if (ctx->debug)
|
||||
log(" node %s\n", ctx->getWireName(cursor).c_str(ctx));
|
||||
if (ctx->debug) {
|
||||
delay_t path_delay_delta = ctx->estimateDelay(cursor, dst_wire) - accumulated_path_delay;
|
||||
|
||||
if (pip == PipId())
|
||||
NPNR_ASSERT(cursor == src_wire);
|
||||
log(" node %s (%+.2f %+.2f)\n", ctx->nameOfWire(cursor), ctx->getDelayNS(path_delay_delta),
|
||||
ctx->getDelayNS(path_delay_delta - last_path_delay_delta));
|
||||
|
||||
last_path_delay_delta = path_delay_delta;
|
||||
|
||||
if (pip != PipId())
|
||||
accumulated_path_delay += ctx->getPipDelay(pip).maxDelay();
|
||||
accumulated_path_delay += ctx->getWireDelay(cursor).maxDelay();
|
||||
}
|
||||
|
||||
if (pip == PipId())
|
||||
NPNR_ASSERT(cursor == src_wire);
|
||||
|
||||
if (!net_info->wires.count(cursor) || net_info->wires.at(cursor).pip != pip) {
|
||||
if (!ctx->checkWireAvail(cursor)) {
|
||||
@ -631,11 +699,11 @@ struct Router1
|
||||
|
||||
if (pip == PipId()) {
|
||||
if (ctx->debug)
|
||||
log(" bind wire %s\n", ctx->getWireName(cursor).c_str(ctx));
|
||||
log(" bind wire %s\n", ctx->nameOfWire(cursor));
|
||||
ctx->bindWire(cursor, net_info, STRENGTH_WEAK);
|
||||
} else {
|
||||
if (ctx->debug)
|
||||
log(" bind pip %s\n", ctx->getPipName(pip).c_str(ctx));
|
||||
log(" bind pip %s\n", ctx->nameOfPip(pip));
|
||||
ctx->bindPip(pip, net_info, STRENGTH_WEAK);
|
||||
}
|
||||
}
|
||||
@ -670,8 +738,8 @@ Router1Cfg::Router1Cfg(Context *ctx) : Settings(ctx)
|
||||
useEstimate = get<bool>("router1/useEstimate", true);
|
||||
|
||||
wireRipupPenalty = ctx->getRipupDelayPenalty();
|
||||
netRipupPenalty = 10*ctx->getRipupDelayPenalty();
|
||||
reuseBonus = wireRipupPenalty/2;
|
||||
netRipupPenalty = 10 * ctx->getRipupDelayPenalty();
|
||||
reuseBonus = wireRipupPenalty / 2;
|
||||
|
||||
estimatePrecision = 100 * ctx->getRipupDelayPenalty();
|
||||
}
|
||||
@ -702,10 +770,9 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
|
||||
|
||||
while (!router.arc_queue.empty()) {
|
||||
if (++iter_cnt % 1000 == 0) {
|
||||
log_info("%10d | %8d %10d | %4d %5d | %9d\n",
|
||||
iter_cnt, router.arcs_with_ripup, router.arcs_without_ripup,
|
||||
router.arcs_with_ripup - last_arcs_with_ripup,
|
||||
router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size()));
|
||||
log_info("%10d | %8d %10d | %4d %5d | %9d\n", iter_cnt, router.arcs_with_ripup,
|
||||
router.arcs_without_ripup, router.arcs_with_ripup - last_arcs_with_ripup,
|
||||
router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size()));
|
||||
last_arcs_with_ripup = router.arcs_with_ripup;
|
||||
last_arcs_without_ripup = router.arcs_without_ripup;
|
||||
#ifndef NDEBUG
|
||||
@ -719,8 +786,7 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
|
||||
arc_key arc = router.arc_queue_pop();
|
||||
|
||||
if (!router.route_arc(arc, true)) {
|
||||
log_warning("Failed to find a route for arc %d of net %s.\n",
|
||||
arc.user_idx, arc.net_info->name.c_str(ctx));
|
||||
log_warning("Failed to find a route for arc %d of net %s.\n", arc.user_idx, ctx->nameOf(arc.net_info));
|
||||
#ifndef NDEBUG
|
||||
router.check();
|
||||
ctx->check();
|
||||
@ -730,10 +796,9 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
|
||||
}
|
||||
}
|
||||
|
||||
log_info("%10d | %8d %10d | %4d %5d | %9d\n",
|
||||
iter_cnt, router.arcs_with_ripup, router.arcs_without_ripup,
|
||||
router.arcs_with_ripup - last_arcs_with_ripup,
|
||||
router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size()));
|
||||
log_info("%10d | %8d %10d | %4d %5d | %9d\n", iter_cnt, router.arcs_with_ripup, router.arcs_without_ripup,
|
||||
router.arcs_with_ripup - last_arcs_with_ripup, router.arcs_without_ripup - last_arcs_without_ripup,
|
||||
int(router.arc_queue.size()));
|
||||
log_info("Routing complete.\n");
|
||||
|
||||
#ifndef NDEBUG
|
||||
@ -758,165 +823,171 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
|
||||
|
||||
bool Context::checkRoutedDesign() const
|
||||
{
|
||||
const Context *ctx = getCtx();
|
||||
const Context *ctx = getCtx();
|
||||
|
||||
for (auto &net_it : ctx->nets) {
|
||||
NetInfo *net_info = net_it.second.get();
|
||||
for (auto &net_it : ctx->nets) {
|
||||
NetInfo *net_info = net_it.second.get();
|
||||
|
||||
#ifdef ARCH_ECP5
|
||||
if (net_info->is_global)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (ctx->debug)
|
||||
log("checking net %s\n", ctx->nameOf(net_info));
|
||||
|
||||
if (net_info->users.empty()) {
|
||||
if (ctx->debug)
|
||||
log("checking net %s\n", net_info->name.c_str(ctx));
|
||||
|
||||
if (net_info->users.empty()) {
|
||||
if (ctx->debug)
|
||||
log(" net without sinks\n");
|
||||
log_assert(net_info->wires.empty());
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found_unrouted = false;
|
||||
bool found_loop = false;
|
||||
bool found_stub = false;
|
||||
|
||||
struct ExtraWireInfo {
|
||||
int order_num = 0;
|
||||
std::unordered_set<WireId> children;
|
||||
};
|
||||
|
||||
std::unordered_map<WireId, ExtraWireInfo> db;
|
||||
|
||||
for (auto &it : net_info->wires) {
|
||||
WireId w = it.first;
|
||||
PipId p = it.second.pip;
|
||||
|
||||
if (p != PipId()) {
|
||||
log_assert(ctx->getPipDstWire(p) == w);
|
||||
db[ctx->getPipSrcWire(p)].children.insert(w);
|
||||
}
|
||||
}
|
||||
|
||||
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
||||
log_assert(src_wire != WireId());
|
||||
|
||||
if (net_info->wires.count(src_wire) == 0) {
|
||||
if (ctx->debug)
|
||||
log(" source (%s) not bound to net\n", ctx->getWireName(src_wire).c_str(ctx));
|
||||
found_unrouted = true;
|
||||
}
|
||||
|
||||
std::unordered_map<WireId, int> dest_wires;
|
||||
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
||||
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]);
|
||||
log_assert(dst_wire != WireId());
|
||||
dest_wires[dst_wire] = user_idx;
|
||||
|
||||
if (net_info->wires.count(dst_wire) == 0) {
|
||||
if (ctx->debug)
|
||||
log(" sink %d (%s) not bound to net\n", user_idx, ctx->getWireName(dst_wire).c_str(ctx));
|
||||
found_unrouted = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::function<void(WireId, int)> setOrderNum;
|
||||
std::unordered_set<WireId> logged_wires;
|
||||
|
||||
setOrderNum = [&](WireId w, int num) {
|
||||
auto &db_entry = db[w];
|
||||
if (db_entry.order_num != 0) {
|
||||
found_loop = true;
|
||||
log(" %*s=> loop\n", 2*num, "");
|
||||
return;
|
||||
}
|
||||
db_entry.order_num = num;
|
||||
for (WireId child : db_entry.children) {
|
||||
if (ctx->debug) {
|
||||
log(" %*s-> %s\n", 2*num, "", ctx->getWireName(child).c_str(ctx));
|
||||
logged_wires.insert(child);
|
||||
}
|
||||
setOrderNum(child, num+1);
|
||||
}
|
||||
if (db_entry.children.empty()) {
|
||||
if (dest_wires.count(w) != 0) {
|
||||
if (ctx->debug)
|
||||
log(" %*s=> sink %d\n", 2*num, "", dest_wires.at(w));
|
||||
} else {
|
||||
if (ctx->debug)
|
||||
log(" %*s=> stub\n", 2*num, "");
|
||||
found_stub = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (ctx->debug) {
|
||||
log(" driver: %s\n", ctx->getWireName(src_wire).c_str(ctx));
|
||||
logged_wires.insert(src_wire);
|
||||
}
|
||||
setOrderNum(src_wire, 1);
|
||||
|
||||
std::unordered_set<WireId> dangling_wires;
|
||||
|
||||
for (auto &it : db) {
|
||||
auto &db_entry = it.second;
|
||||
if (db_entry.order_num == 0)
|
||||
dangling_wires.insert(it.first);
|
||||
}
|
||||
|
||||
if (ctx->debug) {
|
||||
if (dangling_wires.empty()) {
|
||||
log(" no dangling wires.\n");
|
||||
} else {
|
||||
std::unordered_set<WireId> root_wires = dangling_wires;
|
||||
|
||||
for (WireId w : dangling_wires) {
|
||||
for (WireId c : db[w].children)
|
||||
root_wires.erase(c);
|
||||
}
|
||||
|
||||
for (WireId w : root_wires) {
|
||||
log(" dangling wire: %s\n", ctx->getWireName(w).c_str(ctx));
|
||||
logged_wires.insert(w);
|
||||
setOrderNum(w, 1);
|
||||
}
|
||||
|
||||
for (WireId w : dangling_wires) {
|
||||
if (logged_wires.count(w) == 0)
|
||||
log(" loop: %s -> %s\n",
|
||||
ctx->getWireName(ctx->getPipSrcWire(net_info->wires.at(w).pip)).c_str(ctx),
|
||||
ctx->getWireName(w).c_str(ctx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool fail = false;
|
||||
|
||||
if (found_unrouted) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found unrouted arcs\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (found_loop) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found loops\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (found_stub) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found stubs\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (!dangling_wires.empty()) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found dangling wires\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (fail)
|
||||
return false;
|
||||
log(" net without sinks\n");
|
||||
log_assert(net_info->wires.empty());
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
bool found_unrouted = false;
|
||||
bool found_loop = false;
|
||||
bool found_stub = false;
|
||||
|
||||
struct ExtraWireInfo
|
||||
{
|
||||
int order_num = 0;
|
||||
std::unordered_set<WireId> children;
|
||||
};
|
||||
|
||||
std::unordered_map<WireId, ExtraWireInfo> db;
|
||||
|
||||
for (auto &it : net_info->wires) {
|
||||
WireId w = it.first;
|
||||
PipId p = it.second.pip;
|
||||
|
||||
if (p != PipId()) {
|
||||
log_assert(ctx->getPipDstWire(p) == w);
|
||||
db[ctx->getPipSrcWire(p)].children.insert(w);
|
||||
}
|
||||
}
|
||||
|
||||
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
||||
log_assert(src_wire != WireId());
|
||||
|
||||
if (net_info->wires.count(src_wire) == 0) {
|
||||
if (ctx->debug)
|
||||
log(" source (%s) not bound to net\n", ctx->nameOfWire(src_wire));
|
||||
found_unrouted = true;
|
||||
}
|
||||
|
||||
std::unordered_map<WireId, int> dest_wires;
|
||||
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
||||
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]);
|
||||
log_assert(dst_wire != WireId());
|
||||
dest_wires[dst_wire] = user_idx;
|
||||
|
||||
if (net_info->wires.count(dst_wire) == 0) {
|
||||
if (ctx->debug)
|
||||
log(" sink %d (%s) not bound to net\n", user_idx, ctx->nameOfWire(dst_wire));
|
||||
found_unrouted = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::function<void(WireId, int)> setOrderNum;
|
||||
std::unordered_set<WireId> logged_wires;
|
||||
|
||||
setOrderNum = [&](WireId w, int num) {
|
||||
auto &db_entry = db[w];
|
||||
if (db_entry.order_num != 0) {
|
||||
found_loop = true;
|
||||
log(" %*s=> loop\n", 2 * num, "");
|
||||
return;
|
||||
}
|
||||
db_entry.order_num = num;
|
||||
for (WireId child : db_entry.children) {
|
||||
if (ctx->debug) {
|
||||
log(" %*s-> %s\n", 2 * num, "", ctx->nameOfWire(child));
|
||||
logged_wires.insert(child);
|
||||
}
|
||||
setOrderNum(child, num + 1);
|
||||
}
|
||||
if (db_entry.children.empty()) {
|
||||
if (dest_wires.count(w) != 0) {
|
||||
if (ctx->debug)
|
||||
log(" %*s=> sink %d\n", 2 * num, "", dest_wires.at(w));
|
||||
} else {
|
||||
if (ctx->debug)
|
||||
log(" %*s=> stub\n", 2 * num, "");
|
||||
found_stub = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (ctx->debug) {
|
||||
log(" driver: %s\n", ctx->nameOfWire(src_wire));
|
||||
logged_wires.insert(src_wire);
|
||||
}
|
||||
setOrderNum(src_wire, 1);
|
||||
|
||||
std::unordered_set<WireId> dangling_wires;
|
||||
|
||||
for (auto &it : db) {
|
||||
auto &db_entry = it.second;
|
||||
if (db_entry.order_num == 0)
|
||||
dangling_wires.insert(it.first);
|
||||
}
|
||||
|
||||
if (ctx->debug) {
|
||||
if (dangling_wires.empty()) {
|
||||
log(" no dangling wires.\n");
|
||||
} else {
|
||||
std::unordered_set<WireId> root_wires = dangling_wires;
|
||||
|
||||
for (WireId w : dangling_wires) {
|
||||
for (WireId c : db[w].children)
|
||||
root_wires.erase(c);
|
||||
}
|
||||
|
||||
for (WireId w : root_wires) {
|
||||
log(" dangling wire: %s\n", ctx->nameOfWire(w));
|
||||
logged_wires.insert(w);
|
||||
setOrderNum(w, 1);
|
||||
}
|
||||
|
||||
for (WireId w : dangling_wires) {
|
||||
if (logged_wires.count(w) == 0)
|
||||
log(" loop: %s -> %s\n",
|
||||
ctx->nameOfWire(ctx->getPipSrcWire(net_info->wires.at(w).pip)),
|
||||
ctx->nameOfWire(w));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool fail = false;
|
||||
|
||||
if (found_unrouted) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found unrouted arcs\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (found_loop) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found loops\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (found_stub) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found stubs\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (!dangling_wires.empty()) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found dangling wires\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (fail)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay,
|
||||
|
@ -30,15 +30,15 @@ delay_t maxDelay() const { return delay; }
|
||||
|
||||
### BelId
|
||||
|
||||
A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<BelId>`.
|
||||
A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<BelId>`.
|
||||
|
||||
### WireId
|
||||
|
||||
A type representing a wire name. `WireId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<WireId>`.
|
||||
A type representing a wire name. `WireId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<WireId>`.
|
||||
|
||||
### PipId
|
||||
|
||||
A type representing a pip name. `PipId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<PipId>`.
|
||||
A type representing a pip name. `PipId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<PipId>`.
|
||||
|
||||
### GroupId
|
||||
|
||||
|
89
docs/faq.md
89
docs/faq.md
@ -38,7 +38,94 @@ For nextpnr we are using the following terminology.
|
||||
Adding new architectures to nextpnr
|
||||
-----------------------------------
|
||||
|
||||
TBD
|
||||
### Implementing new architectures
|
||||
|
||||
Each nextpnr architecture must implement the *nextpnr architecture API*.
|
||||
See [archapi.md](archapi.md) for a complete reference of the architecture API.
|
||||
|
||||
### Delay Estimates
|
||||
|
||||
Each architecture must implement a `estimateDelay()` method that estimates the expected delay for a path from given `src` to `dst` wires.
|
||||
*It is very important that this method slightly overestimates the expected delay.* Furthermore, it should overestimate the expected delay
|
||||
by a slightly larger margin for longer paths than for shorter paths. Otherwise there will be performance issues with the router.
|
||||
|
||||
The delays estimates returned by that method should also be as fine-grain as possible. It definitely pays off to spend some time improving the `estimateDelay()`
|
||||
for your architecture once implementing small designs work.
|
||||
|
||||
### Ripup Information
|
||||
|
||||
The `getConflictingWireWire()`, `getConflictingWireNet()`, `getConflictingPipWire()`, and `getConflictingPipNet()` methods are used by the router
|
||||
to determine which resources to rip up in order to make a given routing resource (wire or pip) available.
|
||||
|
||||
The architecture must guanrantee that the following invariants hold.
|
||||
|
||||
**Invariant 1:**
|
||||
|
||||
```
|
||||
if (!ctx->checkWireAvail(wire)) {
|
||||
WireId w = getConflictingWireWire(wire);
|
||||
if (w != WireId()) {
|
||||
ctx->unbindWire(w);
|
||||
assert(ctx->checkWireAvail(wire));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Invariant 2:**
|
||||
|
||||
```
|
||||
if (!ctx->checkWireAvail(wire)) {
|
||||
NetInfo *n = getConflictingWireNet(wire);
|
||||
if (n != nullptr) {
|
||||
for (auto &it : n->wires)
|
||||
ctx->unbindWire(it.first);
|
||||
assert(ctx->checkWireAvail(wire));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Invariant 3:**
|
||||
|
||||
```
|
||||
if (!ctx->checkPipAvail(pip)) {
|
||||
WireId w = getConflictingPipWire(pip);
|
||||
if (w != WireId()) {
|
||||
ctx->unbindWire(w);
|
||||
assert(ctx->checkPipAvail(pip));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Invariant 4:**
|
||||
|
||||
```
|
||||
if (!ctx->checkPipAvail(pip)) {
|
||||
NetInfo *n = getConflictingPipNet(pip);
|
||||
if (n != nullptr) {
|
||||
for (auto &it : n->wires)
|
||||
ctx->unbindWire(it.first);
|
||||
assert(ctx->checkPipAvail(pip));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Invariant 5:**
|
||||
|
||||
```
|
||||
if (ctx->checkWireAvail(wire)) {
|
||||
// bind is guaranteed to succeed
|
||||
ctx->bindWire(wire, net, strength);
|
||||
}
|
||||
```
|
||||
|
||||
**Invariant 6:**
|
||||
|
||||
```
|
||||
if (ctx->checkPipAvail(pip) && ctx->checkWireAvail(ctx->getPipDstWire(pip))) {
|
||||
// bind is guaranteed to succeed
|
||||
ctx->bindPip(pip, net, strength);
|
||||
}
|
||||
```
|
||||
|
||||
Nextpnr and other tools
|
||||
-----------------------
|
||||
|
@ -400,7 +400,7 @@ BelId Arch::getBelByLocation(Loc loc) const
|
||||
|
||||
delay_t Arch::estimateDelay(WireId src, WireId dst) const
|
||||
{
|
||||
return 100 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y));
|
||||
return 170 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y));
|
||||
}
|
||||
|
||||
delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
||||
@ -409,7 +409,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
||||
auto driver_loc = getBelLocation(driver.cell->bel);
|
||||
auto sink_loc = getBelLocation(sink.cell->bel);
|
||||
|
||||
return 100 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y));
|
||||
return 170 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y));
|
||||
}
|
||||
|
||||
bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; }
|
||||
|
10
ecp5/arch.h
10
ecp5/arch.h
@ -619,10 +619,7 @@ struct Arch : BaseCtx
|
||||
return wire_to_net.at(wire);
|
||||
}
|
||||
|
||||
WireId getConflictingWireWire(WireId wire) const
|
||||
{
|
||||
return wire;
|
||||
}
|
||||
WireId getConflictingWireWire(WireId wire) const { return wire; }
|
||||
|
||||
NetInfo *getConflictingWireNet(WireId wire) const
|
||||
{
|
||||
@ -729,10 +726,7 @@ struct Arch : BaseCtx
|
||||
return pip_to_net.at(pip);
|
||||
}
|
||||
|
||||
WireId getConflictingPipWire(PipId pip) const
|
||||
{
|
||||
return WireId();
|
||||
}
|
||||
WireId getConflictingPipWire(PipId pip) const { return WireId(); }
|
||||
|
||||
NetInfo *getConflictingPipNet(PipId pip) const
|
||||
{
|
||||
|
@ -75,6 +75,7 @@ struct Location
|
||||
|
||||
bool operator==(const Location &other) const { return x == other.x && y == other.y; }
|
||||
bool operator!=(const Location &other) const { return x != other.x || y != other.y; }
|
||||
bool operator<(const Location &other) const { return y == other.y ? x < other.x : y < other.y; }
|
||||
};
|
||||
|
||||
inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); }
|
||||
@ -86,6 +87,7 @@ struct BelId
|
||||
|
||||
bool operator==(const BelId &other) const { return index == other.index && location == other.location; }
|
||||
bool operator!=(const BelId &other) const { return index != other.index || location != other.location; }
|
||||
bool operator<(const BelId &other) const { return location == other.location ? index < other.index : location < other.location; }
|
||||
};
|
||||
|
||||
struct WireId
|
||||
@ -95,6 +97,7 @@ struct WireId
|
||||
|
||||
bool operator==(const WireId &other) const { return index == other.index && location == other.location; }
|
||||
bool operator!=(const WireId &other) const { return index != other.index || location != other.location; }
|
||||
bool operator<(const WireId &other) const { return location == other.location ? index < other.index : location < other.location; }
|
||||
};
|
||||
|
||||
struct PipId
|
||||
@ -104,6 +107,7 @@ struct PipId
|
||||
|
||||
bool operator==(const PipId &other) const { return index == other.index && location == other.location; }
|
||||
bool operator!=(const PipId &other) const { return index != other.index || location != other.location; }
|
||||
bool operator<(const PipId &other) const { return location == other.location ? index < other.index : location < other.location; }
|
||||
};
|
||||
|
||||
struct GroupId
|
||||
|
@ -453,8 +453,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
|
||||
addProperty(topItem, QVariant::String, "Type", ctx->getWireType(wire).c_str(ctx));
|
||||
addProperty(topItem, QVariant::Bool, "Available", ctx->checkWireAvail(wire));
|
||||
addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundWireNet(wire)), ElementType::NET);
|
||||
addProperty(topItem, QVariant::String, "Conflicting Wire", ctx->getWireName(ctx->getConflictingWireWire(wire)).c_str(ctx),
|
||||
ElementType::WIRE);
|
||||
addProperty(topItem, QVariant::String, "Conflicting Wire",
|
||||
ctx->getWireName(ctx->getConflictingWireWire(wire)).c_str(ctx), ElementType::WIRE);
|
||||
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)),
|
||||
ElementType::NET);
|
||||
|
||||
@ -515,8 +515,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
|
||||
addProperty(topItem, QVariant::String, "Type", ctx->getPipType(pip).c_str(ctx));
|
||||
addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip));
|
||||
addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundPipNet(pip)), ElementType::NET);
|
||||
addProperty(topItem, QVariant::String, "Conflicting Wire", ctx->getWireName(ctx->getConflictingPipWire(pip)).c_str(ctx),
|
||||
ElementType::WIRE);
|
||||
addProperty(topItem, QVariant::String, "Conflicting Wire",
|
||||
ctx->getWireName(ctx->getConflictingPipWire(pip)).c_str(ctx), ElementType::WIRE);
|
||||
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingPipNet(pip)),
|
||||
ElementType::NET);
|
||||
addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx),
|
||||
|
@ -566,10 +566,7 @@ struct Arch : BaseCtx
|
||||
return wire_to_net[wire.index];
|
||||
}
|
||||
|
||||
WireId getConflictingWireWire(WireId wire) const
|
||||
{
|
||||
return wire;
|
||||
}
|
||||
WireId getConflictingWireWire(WireId wire) const { return wire; }
|
||||
|
||||
NetInfo *getConflictingWireNet(WireId wire) const
|
||||
{
|
||||
|
@ -66,6 +66,7 @@ struct BelId
|
||||
|
||||
bool operator==(const BelId &other) const { return index == other.index; }
|
||||
bool operator!=(const BelId &other) const { return index != other.index; }
|
||||
bool operator<(const BelId &other) const { return index < other.index; }
|
||||
};
|
||||
|
||||
struct WireId
|
||||
@ -74,6 +75,7 @@ struct WireId
|
||||
|
||||
bool operator==(const WireId &other) const { return index == other.index; }
|
||||
bool operator!=(const WireId &other) const { return index != other.index; }
|
||||
bool operator<(const WireId &other) const { return index < other.index; }
|
||||
};
|
||||
|
||||
struct PipId
|
||||
@ -82,6 +84,7 @@ struct PipId
|
||||
|
||||
bool operator==(const PipId &other) const { return index == other.index; }
|
||||
bool operator!=(const PipId &other) const { return index != other.index; }
|
||||
bool operator<(const PipId &other) const { return index < other.index; }
|
||||
};
|
||||
|
||||
struct GroupId
|
||||
|
Loading…
Reference in New Issue
Block a user