Merge branch 'router_improve' of https://github.com/YosysHQ/nextpnr into xc7-router_improve
This commit is contained in:
commit
19561fde52
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "nextpnr.h"
|
||||
#include "log.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
@ -25,6 +26,7 @@ assertion_failure::assertion_failure(std::string msg, std::string expr_str, std:
|
||||
: runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg),
|
||||
expr_str(expr_str), filename(filename), line(line)
|
||||
{
|
||||
log_flush();
|
||||
}
|
||||
|
||||
void IdString::set(const BaseCtx *ctx, const std::string &s)
|
||||
|
@ -99,7 +99,7 @@ struct Router1
|
||||
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue;
|
||||
|
||||
std::unordered_map<WireId, int> wireScores;
|
||||
std::unordered_map<PipId, int> pipScores;
|
||||
std::unordered_map<NetInfo*, int> netScores;
|
||||
|
||||
int arcs_with_ripup = 0;
|
||||
int arcs_without_ripup = 0;
|
||||
@ -124,6 +124,9 @@ struct Router1
|
||||
|
||||
void arc_queue_insert(const arc_key &arc)
|
||||
{
|
||||
if (queued_arcs.count(arc))
|
||||
return;
|
||||
|
||||
NetInfo *net_info = arc.net_info;
|
||||
int user_idx = arc.user_idx;
|
||||
|
||||
@ -146,76 +149,79 @@ struct Router1
|
||||
if (ctx->debug)
|
||||
log(" ripup net %s\n", net->name.c_str(ctx));
|
||||
|
||||
netScores[net]++;
|
||||
|
||||
auto net_wires_copy = net->wires;
|
||||
for (auto &it : net_wires_copy) {
|
||||
if (it.second.pip == PipId())
|
||||
ripup_wire(it.first, true);
|
||||
else
|
||||
ripup_pip(it.second.pip, true);
|
||||
WireId w = it.first;
|
||||
|
||||
for (auto &it : wire_to_arcs[w]) {
|
||||
arc_to_wires[it].erase(w);
|
||||
arc_queue_insert(it);
|
||||
}
|
||||
wire_to_arcs[w].clear();
|
||||
|
||||
if (ctx->debug)
|
||||
log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx));
|
||||
|
||||
ctx->unbindWire(w);
|
||||
wireScores[w]++;
|
||||
}
|
||||
|
||||
ripup_flag = true;
|
||||
}
|
||||
|
||||
void ripup_wire(WireId wire, bool extra_indent = false)
|
||||
void ripup_wire(WireId wire, int extra_indent = 0)
|
||||
{
|
||||
if (ctx->debug)
|
||||
log(" %sripup wire %s\n", extra_indent ? " " : "", ctx->getWireName(wire).c_str(ctx));
|
||||
log(" ripup wire %s\n", ctx->getWireName(wire).c_str(ctx));
|
||||
|
||||
wireScores[wire]++;
|
||||
WireId w = ctx->getConflictingWireWire(wire);
|
||||
|
||||
if (ctx->getBoundWireNet(wire)) {
|
||||
for (auto &it : wire_to_arcs[wire]) {
|
||||
arc_to_wires[it].erase(wire);
|
||||
if (w == WireId()) {
|
||||
NetInfo *n = ctx->getConflictingWireNet(wire);
|
||||
if (n != nullptr)
|
||||
ripup_net(n);
|
||||
} else {
|
||||
for (auto &it : wire_to_arcs[w]) {
|
||||
arc_to_wires[it].erase(w);
|
||||
arc_queue_insert(it);
|
||||
}
|
||||
wire_to_arcs[wire].clear();
|
||||
ctx->unbindWire(wire);
|
||||
}
|
||||
wire_to_arcs[w].clear();
|
||||
|
||||
NetInfo *net = ctx->getConflictingWireNet(wire);
|
||||
if (net != nullptr) {
|
||||
wireScores[wire] += net->wires.size();
|
||||
ripup_net(net);
|
||||
if (ctx->debug)
|
||||
log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx));
|
||||
|
||||
ctx->unbindWire(w);
|
||||
wireScores[w]++;
|
||||
}
|
||||
|
||||
ripup_flag = true;
|
||||
}
|
||||
|
||||
void ripup_pip(PipId pip, bool extra_indent = false)
|
||||
void ripup_pip(PipId pip)
|
||||
{
|
||||
WireId wire = ctx->getPipDstWire(pip);
|
||||
|
||||
if (ctx->debug)
|
||||
log(" %sripup pip %s (%s)\n", extra_indent ? " " : "", ctx->getPipName(pip).c_str(ctx), ctx->getWireName(wire).c_str(ctx));
|
||||
log(" ripup pip %s\n", ctx->getPipName(pip).c_str(ctx));
|
||||
|
||||
wireScores[wire]++;
|
||||
pipScores[pip]++;
|
||||
WireId w = ctx->getConflictingPipWire(pip);
|
||||
|
||||
if (ctx->getBoundPipNet(pip)) {
|
||||
ctx->unbindPip(pip);
|
||||
goto remove_wire_arcs;
|
||||
}
|
||||
|
||||
if (ctx->getBoundWireNet(wire)) {
|
||||
ctx->unbindWire(wire);
|
||||
goto remove_wire_arcs;
|
||||
}
|
||||
|
||||
if (0) {
|
||||
remove_wire_arcs:
|
||||
for (auto &it : wire_to_arcs[wire]) {
|
||||
arc_to_wires[it].erase(wire);
|
||||
if (w == WireId()) {
|
||||
NetInfo *n = ctx->getConflictingPipNet(pip);
|
||||
if (n != nullptr)
|
||||
ripup_net(n);
|
||||
} else {
|
||||
for (auto &it : wire_to_arcs[w]) {
|
||||
arc_to_wires[it].erase(w);
|
||||
arc_queue_insert(it);
|
||||
}
|
||||
wire_to_arcs[wire].clear();
|
||||
}
|
||||
wire_to_arcs[w].clear();
|
||||
|
||||
NetInfo *net = ctx->getConflictingPipNet(pip);
|
||||
if (net != nullptr) {
|
||||
wireScores[wire] += net->wires.size();
|
||||
pipScores[pip] += net->wires.size();
|
||||
ripup_net(net);
|
||||
if (ctx->debug)
|
||||
log(" unbind wire %s\n", ctx->getWireName(w).c_str(ctx));
|
||||
|
||||
ctx->unbindWire(w);
|
||||
wireScores[w]++;
|
||||
}
|
||||
|
||||
ripup_flag = true;
|
||||
@ -247,6 +253,8 @@ remove_wire_arcs:
|
||||
if (skip_net(net_info))
|
||||
continue;
|
||||
|
||||
// log("[check] net: %s\n", net_info->name.c_str(ctx));
|
||||
|
||||
auto src_wire = ctx->getNetinfoSourceWire(net_info);
|
||||
log_assert(src_wire != WireId());
|
||||
|
||||
@ -259,8 +267,10 @@ remove_wire_arcs:
|
||||
arc.user_idx = user_idx;
|
||||
|
||||
valid_arcs.insert(arc);
|
||||
// log("[check] arc: %s %s\n", ctx->getWireName(src_wire).c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx));
|
||||
|
||||
for (WireId wire : arc_to_wires[arc]) {
|
||||
// log("[check] wire: %s\n", ctx->getWireName(wire).c_str(ctx));
|
||||
valid_wires_for_net.insert(wire);
|
||||
log_assert(wire_to_arcs[wire].count(arc));
|
||||
log_assert(net_info->wires.count(wire));
|
||||
@ -285,6 +295,9 @@ remove_wire_arcs:
|
||||
|
||||
void setup()
|
||||
{
|
||||
std::unordered_map<WireId, NetInfo*> src_to_net;
|
||||
std::unordered_map<WireId, arc_key> dst_to_arc;
|
||||
|
||||
for (auto &net_it : ctx->nets)
|
||||
{
|
||||
NetInfo *net_info = net_it.second.get();
|
||||
@ -298,6 +311,14 @@ remove_wire_arcs:
|
||||
log_error("No wire found for port %s on source cell %s.\n", net_info->driver.port.c_str(ctx),
|
||||
net_info->driver.cell->name.c_str(ctx));
|
||||
|
||||
if (src_to_net.count(src_wire))
|
||||
log_error("Found two nets with same source wire %s: %s vs %s\n", ctx->getWireName(src_wire).c_str(ctx),
|
||||
ctx->nameOf(net_info), ctx->nameOf(src_to_net.at(src_wire)));
|
||||
|
||||
if (dst_to_arc.count(src_wire))
|
||||
log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n", ctx->getWireName(src_wire).c_str(ctx),
|
||||
ctx->nameOf(net_info), ctx->nameOf(dst_to_arc.at(src_wire).net_info), dst_to_arc.at(src_wire).user_idx);
|
||||
|
||||
for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) {
|
||||
auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]);
|
||||
|
||||
@ -305,10 +326,23 @@ remove_wire_arcs:
|
||||
log_error("No wire found for port %s on destination cell %s.\n", net_info->users[user_idx].port.c_str(ctx),
|
||||
net_info->users[user_idx].cell->name.c_str(ctx));
|
||||
|
||||
if (dst_to_arc.count(dst_wire)) {
|
||||
if (dst_to_arc.at(dst_wire).net_info == net_info)
|
||||
continue;
|
||||
log_error("Found two arcs with same sink wire %s: %s (%d) vs %s (%d)\n", ctx->getWireName(dst_wire).c_str(ctx),
|
||||
ctx->nameOf(net_info), user_idx, ctx->nameOf(dst_to_arc.at(dst_wire).net_info), dst_to_arc.at(dst_wire).user_idx);
|
||||
}
|
||||
|
||||
if (src_to_net.count(dst_wire))
|
||||
log_error("Wire %s is used as source and sink in different nets: %s vs %s (%d)\n", ctx->getWireName(dst_wire).c_str(ctx),
|
||||
ctx->nameOf(src_to_net.at(dst_wire)), ctx->nameOf(net_info), user_idx);
|
||||
|
||||
arc_key arc;
|
||||
arc.net_info = net_info;
|
||||
arc.user_idx = user_idx;
|
||||
|
||||
dst_to_arc[dst_wire] = arc;
|
||||
|
||||
if (net_info->wires.count(src_wire) == 0) {
|
||||
arc_queue_insert(arc, src_wire, dst_wire);
|
||||
continue;
|
||||
@ -332,6 +366,8 @@ remove_wire_arcs:
|
||||
}
|
||||
}
|
||||
|
||||
src_to_net[src_wire] = net_info;
|
||||
|
||||
std::vector<WireId> unbind_wires;
|
||||
|
||||
for (auto &it : net_info->wires)
|
||||
@ -420,43 +456,74 @@ remove_wire_arcs:
|
||||
WireId next_wire = ctx->getPipDstWire(pip);
|
||||
next_delay += ctx->getWireDelay(next_wire).maxDelay();
|
||||
|
||||
if (!ctx->checkWireAvail(next_wire)) {
|
||||
NetInfo *ripupWireNet = ctx->getConflictingWireNet(next_wire);
|
||||
WireId conflictWireWire = WireId(), conflictPipWire = WireId();
|
||||
NetInfo *conflictWireNet = nullptr, *conflictPipNet = nullptr;
|
||||
|
||||
if (ripupWireNet == nullptr)
|
||||
continue;
|
||||
|
||||
if (ripupWireNet == net_info) {
|
||||
next_bonus += cfg.wireReuseBonus;
|
||||
} else {
|
||||
if (net_info->wires.count(next_wire) && net_info->wires.at(next_wire).pip == pip) {
|
||||
next_bonus += cfg.reuseBonus;
|
||||
} else {
|
||||
if (!ctx->checkWireAvail(next_wire)) {
|
||||
if (!ripup)
|
||||
continue;
|
||||
conflictWireWire = ctx->getConflictingWireWire(next_wire);
|
||||
if (conflictWireWire == WireId()) {
|
||||
conflictWireNet = ctx->getConflictingWireNet(next_wire);
|
||||
if (conflictWireNet == nullptr)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto scores_it = wireScores.find(next_wire);
|
||||
if (!ctx->checkPipAvail(pip)) {
|
||||
if (!ripup)
|
||||
continue;
|
||||
conflictPipWire = ctx->getConflictingPipWire(pip);
|
||||
if (conflictPipWire == WireId()) {
|
||||
conflictPipNet = ctx->getConflictingPipNet(pip);
|
||||
if (conflictPipNet == nullptr)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (conflictWireNet != nullptr && conflictPipWire != WireId() && conflictWireNet->wires.count(conflictPipWire))
|
||||
conflictPipWire = WireId();
|
||||
|
||||
if (conflictPipNet != nullptr && conflictWireWire != WireId() && conflictPipNet->wires.count(conflictWireWire))
|
||||
conflictWireWire = WireId();
|
||||
|
||||
if (conflictWireWire == conflictPipWire)
|
||||
conflictWireWire = WireId();
|
||||
|
||||
if (conflictWireNet == conflictPipNet)
|
||||
conflictWireNet = nullptr;
|
||||
|
||||
if (conflictWireWire != WireId()) {
|
||||
auto scores_it = wireScores.find(conflictWireWire);
|
||||
if (scores_it != wireScores.end())
|
||||
next_penalty += scores_it->second * cfg.wireRipupPenalty;
|
||||
else
|
||||
next_penalty += cfg.wireRipupPenalty;
|
||||
next_penalty += cfg.wireRipupPenalty;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx->checkPipAvail(pip)) {
|
||||
NetInfo *ripupPipNet = ctx->getConflictingPipNet(pip);
|
||||
if (conflictPipWire != WireId()) {
|
||||
auto scores_it = wireScores.find(conflictPipWire);
|
||||
if (scores_it != wireScores.end())
|
||||
next_penalty += scores_it->second * cfg.wireRipupPenalty;
|
||||
next_penalty += cfg.wireRipupPenalty;
|
||||
}
|
||||
|
||||
if (ripupPipNet == nullptr)
|
||||
continue;
|
||||
if (conflictWireNet != nullptr) {
|
||||
auto scores_it = netScores.find(conflictWireNet);
|
||||
if (scores_it != netScores.end())
|
||||
next_penalty += scores_it->second * cfg.netRipupPenalty;
|
||||
next_penalty += cfg.netRipupPenalty;
|
||||
next_penalty += conflictWireNet->wires.size() * cfg.wireRipupPenalty;
|
||||
}
|
||||
|
||||
if (ripupPipNet == net_info) {
|
||||
next_bonus += cfg.pipReuseBonus;
|
||||
} else {
|
||||
if (!ripup)
|
||||
continue;
|
||||
|
||||
auto scores_it = pipScores.find(pip);
|
||||
if (scores_it != pipScores.end())
|
||||
next_penalty += scores_it->second * cfg.pipRipupPenalty;
|
||||
else
|
||||
next_penalty += cfg.pipRipupPenalty;
|
||||
if (conflictPipNet != nullptr) {
|
||||
auto scores_it = netScores.find(conflictPipNet);
|
||||
if (scores_it != netScores.end())
|
||||
next_penalty += scores_it->second * cfg.netRipupPenalty;
|
||||
next_penalty += cfg.netRipupPenalty;
|
||||
next_penalty += conflictPipNet->wires.size() * cfg.wireRipupPenalty;
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,9 +542,6 @@ remove_wire_arcs:
|
||||
if (next_score + ctx->getDelayEpsilon() >= old_score)
|
||||
continue;
|
||||
|
||||
if (next_delay + ctx->getDelayEpsilon() >= old_delay)
|
||||
continue;
|
||||
|
||||
#if 0
|
||||
if (ctx->debug)
|
||||
log("Found better route to %s. Old vs new delay estimate: %.3f (%.3f) %.3f (%.3f)\n",
|
||||
@ -534,47 +598,44 @@ remove_wire_arcs:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctx->debug) {
|
||||
log(" final route delay: %8.2f\n", ctx->getDelayNS(visited[dst_wire].delay));
|
||||
log(" final route penalty: %8.2f\n", ctx->getDelayNS(visited[dst_wire].penalty));
|
||||
log(" final route bonus: %8.2f\n", ctx->getDelayNS(visited[dst_wire].bonus));
|
||||
}
|
||||
|
||||
// bind resulting route (and maybe unroute other nets)
|
||||
|
||||
std::unordered_set<WireId> unassign_wires = arc_to_wires[arc];
|
||||
|
||||
WireId cursor = dst_wire;
|
||||
while (1) {
|
||||
auto pip = visited[cursor].pip;
|
||||
|
||||
if (ctx->debug)
|
||||
log(" node %s\n", ctx->getWireName(cursor).c_str(ctx));
|
||||
|
||||
if (!ctx->checkWireAvail(cursor)) {
|
||||
NetInfo *ripupWireNet = ctx->getConflictingWireNet(cursor);
|
||||
NPNR_ASSERT(ripupWireNet != nullptr);
|
||||
if (pip == PipId())
|
||||
NPNR_ASSERT(cursor == src_wire);
|
||||
|
||||
if (ripupWireNet != net_info) {
|
||||
if (!net_info->wires.count(cursor) || net_info->wires.at(cursor).pip != pip) {
|
||||
if (!ctx->checkWireAvail(cursor)) {
|
||||
ripup_wire(cursor);
|
||||
NPNR_ASSERT(ctx->checkWireAvail(cursor));
|
||||
}
|
||||
}
|
||||
|
||||
auto pip = visited[cursor].pip;
|
||||
|
||||
if (pip == PipId()) {
|
||||
NPNR_ASSERT(cursor == src_wire);
|
||||
} else {
|
||||
if (!ctx->checkPipAvail(pip)) {
|
||||
NetInfo *ripupPipNet = ctx->getConflictingPipNet(pip);
|
||||
NPNR_ASSERT(ripupPipNet != nullptr);
|
||||
|
||||
if (ripupPipNet != net_info || net_info->wires.at(cursor).pip != pip)
|
||||
ripup_pip(pip);
|
||||
if (pip != PipId() && !ctx->checkPipAvail(pip)) {
|
||||
ripup_pip(pip);
|
||||
NPNR_ASSERT(ctx->checkPipAvail(pip));
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->checkWireAvail(cursor)) {
|
||||
if (pip == PipId()) {
|
||||
if (ctx->debug)
|
||||
log(" bind %s\n", ctx->getWireName(cursor).c_str(ctx));
|
||||
log(" bind wire %s\n", ctx->getWireName(cursor).c_str(ctx));
|
||||
ctx->bindWire(cursor, net_info, STRENGTH_WEAK);
|
||||
} else if (ctx->checkPipAvail(pip)) {
|
||||
} else {
|
||||
if (ctx->debug)
|
||||
log(" bind %s\n", ctx->getPipName(pip).c_str(ctx));
|
||||
log(" bind pip %s\n", ctx->getPipName(pip).c_str(ctx));
|
||||
ctx->bindPip(pip, net_info, STRENGTH_WEAK);
|
||||
}
|
||||
}
|
||||
@ -609,10 +670,8 @@ Router1Cfg::Router1Cfg(Context *ctx) : Settings(ctx)
|
||||
useEstimate = get<bool>("router1/useEstimate", true);
|
||||
|
||||
wireRipupPenalty = ctx->getRipupDelayPenalty();
|
||||
pipRipupPenalty = ctx->getRipupDelayPenalty();
|
||||
|
||||
wireReuseBonus = wireRipupPenalty/8;
|
||||
pipReuseBonus = pipRipupPenalty/8;
|
||||
netRipupPenalty = 10*ctx->getRipupDelayPenalty();
|
||||
reuseBonus = wireRipupPenalty/2;
|
||||
|
||||
estimatePrecision = 100 * ctx->getRipupDelayPenalty();
|
||||
}
|
||||
@ -649,15 +708,21 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
|
||||
router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size()));
|
||||
last_arcs_with_ripup = router.arcs_with_ripup;
|
||||
last_arcs_without_ripup = router.arcs_without_ripup;
|
||||
#ifndef NDEBUG
|
||||
router.check();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ctx->debug)
|
||||
log("-- %d --\n", iter_cnt);
|
||||
|
||||
arc_key arc = router.arc_queue_pop();
|
||||
|
||||
if (!router.route_arc(arc, true)) {
|
||||
log_warning("Failed to find a route for arc %d of net %s.\n",
|
||||
arc.user_idx, arc.net_info->name.c_str(ctx));
|
||||
#ifndef NDEBUG
|
||||
router.check();
|
||||
ctx->check();
|
||||
#endif
|
||||
ctx->unlock();
|
||||
@ -669,18 +734,17 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
|
||||
iter_cnt, router.arcs_with_ripup, router.arcs_without_ripup,
|
||||
router.arcs_with_ripup - last_arcs_with_ripup,
|
||||
router.arcs_without_ripup - last_arcs_without_ripup, int(router.arc_queue.size()));
|
||||
log_info("Routing complete.\n");
|
||||
|
||||
#ifndef NDEBUG
|
||||
router.check();
|
||||
ctx->check();
|
||||
log_assert(ctx->checkRoutedDesign());
|
||||
#endif
|
||||
|
||||
log_info("Routing complete.\n");
|
||||
ctx->checkRoutedDesign();
|
||||
|
||||
log_info("Checksum: 0x%08x\n", ctx->checksum());
|
||||
#ifndef NDEBUG
|
||||
ctx->check();
|
||||
#endif
|
||||
timing_analysis(ctx, true /* slack_histogram */, true /* print_path */);
|
||||
|
||||
ctx->unlock();
|
||||
return true;
|
||||
} catch (log_execution_error_exception) {
|
||||
@ -772,9 +836,11 @@ bool Context::checkRoutedDesign() const
|
||||
}
|
||||
if (db_entry.children.empty()) {
|
||||
if (dest_wires.count(w) != 0) {
|
||||
log(" %*s=> sink %d\n", 2*num, "", dest_wires.at(w));
|
||||
if (ctx->debug)
|
||||
log(" %*s=> sink %d\n", 2*num, "", dest_wires.at(w));
|
||||
} else {
|
||||
log(" %*s=> stub\n", 2*num, "");
|
||||
if (ctx->debug)
|
||||
log(" %*s=> stub\n", 2*num, "");
|
||||
found_stub = true;
|
||||
}
|
||||
}
|
||||
@ -820,10 +886,34 @@ bool Context::checkRoutedDesign() const
|
||||
}
|
||||
}
|
||||
|
||||
log_assert(!found_unrouted);
|
||||
log_assert(!found_loop);
|
||||
log_assert(!found_stub);
|
||||
log_assert(dangling_wires.empty());
|
||||
bool fail = false;
|
||||
|
||||
if (found_unrouted) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found unrouted arcs\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (found_loop) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found loops\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (found_stub) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found stubs\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (!dangling_wires.empty()) {
|
||||
if (ctx->debug)
|
||||
log("check failed: found dangling wires\n");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (fail)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -34,9 +34,8 @@ struct Router1Cfg : Settings
|
||||
bool fullCleanupReroute;
|
||||
bool useEstimate;
|
||||
delay_t wireRipupPenalty;
|
||||
delay_t pipRipupPenalty;
|
||||
delay_t wireReuseBonus;
|
||||
delay_t pipReuseBonus;
|
||||
delay_t netRipupPenalty;
|
||||
delay_t reuseBonus;
|
||||
delay_t estimatePrecision;
|
||||
};
|
||||
|
||||
|
@ -215,14 +215,15 @@ Return true if the wire is available, i.e. can be bound to a net.
|
||||
|
||||
Return the net a wire is bound to.
|
||||
|
||||
### NetInfo \*getConflictingWireNet(WireId wire) const
|
||||
### WireId getConflictingWireWire(WireId wire) const
|
||||
|
||||
If this returns a non-nullptr, then unbinding that net
|
||||
If this returns a non-WireId(), then unbinding that wire
|
||||
will make the given wire available.
|
||||
|
||||
This returns nullptr if the wire is already available,
|
||||
or if there is no single net that can be unbound to make this
|
||||
wire available.
|
||||
### NetInfo \*getConflictingWireNet(WireId wire) const
|
||||
|
||||
If this returns a non-nullptr, then unbinding that entire net
|
||||
will make the given wire available.
|
||||
|
||||
### DelayInfo getWireDelay(WireId wire) const
|
||||
|
||||
@ -282,18 +283,23 @@ This method must also update `NetInfo::wires`.
|
||||
|
||||
Returns true if the given pip is available to be bound to a net.
|
||||
|
||||
Users must also check if the pip destination wire is available
|
||||
with `checkWireAvail(getPipDstWire(pip))` before binding the
|
||||
pip to a net.
|
||||
|
||||
### NetInfo \*getBoundPipNet(PipId pip) const
|
||||
|
||||
Return the net this pip is bound to.
|
||||
|
||||
### WireId getConflictingPipWire(PipId pip) const
|
||||
|
||||
If this returns a non-WireId(), then unbinding that wire
|
||||
will make the given pip available.
|
||||
|
||||
### NetInfo \*getConflictingPipNet(PipId pip) const
|
||||
|
||||
Return the net that needs to be unbound in order to make this
|
||||
pip available.
|
||||
|
||||
This does not need to (but may) return the conflicting wire if the conflict is
|
||||
limited to the conflicting wire being bound to the destination wire for this
|
||||
pip.
|
||||
If this returns a non-nullptr, then unbinding that entire net
|
||||
will make the given pip available.
|
||||
|
||||
### const\_range\<PipId\> getPips() const
|
||||
|
||||
|
10
ecp5/arch.h
10
ecp5/arch.h
@ -619,6 +619,11 @@ struct Arch : BaseCtx
|
||||
return wire_to_net.at(wire);
|
||||
}
|
||||
|
||||
WireId getConflictingWireWire(WireId wire) const
|
||||
{
|
||||
return wire;
|
||||
}
|
||||
|
||||
NetInfo *getConflictingWireNet(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
@ -724,6 +729,11 @@ struct Arch : BaseCtx
|
||||
return pip_to_net.at(pip);
|
||||
}
|
||||
|
||||
WireId getConflictingPipWire(PipId pip) const
|
||||
{
|
||||
return WireId();
|
||||
}
|
||||
|
||||
NetInfo *getConflictingPipNet(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
|
@ -373,6 +373,8 @@ NetInfo *Arch::getBoundPipNet(PipId pip) const { return pips.at(pip).bound_net;
|
||||
|
||||
NetInfo *Arch::getConflictingPipNet(PipId pip) const { return pips.at(pip).bound_net; }
|
||||
|
||||
WireId Arch::getConflictingPipWire(PipId pip) const { return pips.at(pip).bound_net ? pips.at(pip).dstWire : WireId(); }
|
||||
|
||||
const std::vector<PipId> &Arch::getPips() const { return pip_ids; }
|
||||
|
||||
Loc Arch::getPipLocation(PipId pip) const { return pips.at(pip).loc; }
|
||||
|
@ -172,6 +172,7 @@ struct Arch : BaseCtx
|
||||
void unbindWire(WireId wire);
|
||||
bool checkWireAvail(WireId wire) const;
|
||||
NetInfo *getBoundWireNet(WireId wire) const;
|
||||
WireId getConflictingWireWire(WireId wire) const { return wire; }
|
||||
NetInfo *getConflictingWireNet(WireId wire) const;
|
||||
DelayInfo getWireDelay(WireId wire) const { return DelayInfo(); }
|
||||
const std::vector<WireId> &getWires() const;
|
||||
@ -186,6 +187,7 @@ struct Arch : BaseCtx
|
||||
void unbindPip(PipId pip);
|
||||
bool checkPipAvail(PipId pip) const;
|
||||
NetInfo *getBoundPipNet(PipId pip) const;
|
||||
WireId getConflictingPipWire(PipId pip) const;
|
||||
NetInfo *getConflictingPipNet(PipId pip) const;
|
||||
const std::vector<PipId> &getPips() const;
|
||||
Loc getPipLocation(PipId pip) const;
|
||||
|
@ -453,6 +453,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
|
||||
addProperty(topItem, QVariant::String, "Type", ctx->getWireType(wire).c_str(ctx));
|
||||
addProperty(topItem, QVariant::Bool, "Available", ctx->checkWireAvail(wire));
|
||||
addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundWireNet(wire)), ElementType::NET);
|
||||
addProperty(topItem, QVariant::String, "Conflicting Wire", ctx->getWireName(ctx->getConflictingWireWire(wire)).c_str(ctx),
|
||||
ElementType::WIRE);
|
||||
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)),
|
||||
ElementType::NET);
|
||||
|
||||
@ -513,6 +515,8 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
|
||||
addProperty(topItem, QVariant::String, "Type", ctx->getPipType(pip).c_str(ctx));
|
||||
addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip));
|
||||
addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundPipNet(pip)), ElementType::NET);
|
||||
addProperty(topItem, QVariant::String, "Conflicting Wire", ctx->getWireName(ctx->getConflictingPipWire(pip)).c_str(ctx),
|
||||
ElementType::WIRE);
|
||||
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingPipNet(pip)),
|
||||
ElementType::NET);
|
||||
addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx),
|
||||
|
57
ice40/arch.h
57
ice40/arch.h
@ -404,7 +404,7 @@ struct Arch : BaseCtx
|
||||
std::vector<CellInfo *> bel_to_cell;
|
||||
std::vector<NetInfo *> wire_to_net;
|
||||
std::vector<NetInfo *> pip_to_net;
|
||||
std::vector<NetInfo *> switches_locked;
|
||||
std::vector<WireId> switches_locked;
|
||||
|
||||
ArchArgs args;
|
||||
Arch(ArchArgs args);
|
||||
@ -546,7 +546,7 @@ struct Arch : BaseCtx
|
||||
auto pip = it->second.pip;
|
||||
if (pip != PipId()) {
|
||||
pip_to_net[pip.index] = nullptr;
|
||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr;
|
||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = WireId();
|
||||
}
|
||||
|
||||
net_wires.erase(it);
|
||||
@ -566,6 +566,11 @@ struct Arch : BaseCtx
|
||||
return wire_to_net[wire.index];
|
||||
}
|
||||
|
||||
WireId getConflictingWireWire(WireId wire) const
|
||||
{
|
||||
return wire;
|
||||
}
|
||||
|
||||
NetInfo *getConflictingWireNet(WireId wire) const
|
||||
{
|
||||
NPNR_ASSERT(wire != WireId());
|
||||
@ -608,14 +613,15 @@ struct Arch : BaseCtx
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
NPNR_ASSERT(pip_to_net[pip.index] == nullptr);
|
||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr);
|
||||
|
||||
pip_to_net[pip.index] = net;
|
||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
|
||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == WireId());
|
||||
|
||||
WireId dst;
|
||||
dst.index = chip_info->pip_data[pip.index].dst;
|
||||
NPNR_ASSERT(wire_to_net[dst.index] == nullptr);
|
||||
|
||||
pip_to_net[pip.index] = net;
|
||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = dst;
|
||||
|
||||
wire_to_net[dst.index] = net;
|
||||
net->wires[dst].pip = pip;
|
||||
net->wires[dst].strength = strength;
|
||||
@ -627,7 +633,7 @@ struct Arch : BaseCtx
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
NPNR_ASSERT(pip_to_net[pip.index] != nullptr);
|
||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr);
|
||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != WireId());
|
||||
|
||||
WireId dst;
|
||||
dst.index = chip_info->pip_data[pip.index].dst;
|
||||
@ -636,33 +642,39 @@ struct Arch : BaseCtx
|
||||
pip_to_net[pip.index]->wires.erase(dst);
|
||||
|
||||
pip_to_net[pip.index] = nullptr;
|
||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr;
|
||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = WireId();
|
||||
refreshUiPip(pip);
|
||||
refreshUiWire(dst);
|
||||
}
|
||||
|
||||
bool checkPipAvail(PipId pip) const
|
||||
bool ice40_pip_hard_unavail(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
auto &pi = chip_info->pip_data[pip.index];
|
||||
auto &si = chip_info->bits_info->switches[pi.switch_index];
|
||||
|
||||
if (switches_locked[pi.switch_index] != nullptr)
|
||||
return false;
|
||||
|
||||
if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) {
|
||||
NPNR_ASSERT(si.bel >= 0);
|
||||
if (bel_to_cell[si.bel] != nullptr)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pi.flags & PipInfoPOD::FLAG_NOCARRY) {
|
||||
NPNR_ASSERT(si.bel >= 0);
|
||||
if (bel_carry[si.bel])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool checkPipAvail(PipId pip) const
|
||||
{
|
||||
if (ice40_pip_hard_unavail(pip))
|
||||
return false;
|
||||
|
||||
auto &pi = chip_info->pip_data[pip.index];
|
||||
return switches_locked[pi.switch_index] == WireId();
|
||||
}
|
||||
|
||||
NetInfo *getBoundPipNet(PipId pip) const
|
||||
@ -671,10 +683,21 @@ struct Arch : BaseCtx
|
||||
return pip_to_net[pip.index];
|
||||
}
|
||||
|
||||
WireId getConflictingPipWire(PipId pip) const
|
||||
{
|
||||
if (ice40_pip_hard_unavail(pip))
|
||||
return WireId();
|
||||
|
||||
return switches_locked[chip_info->pip_data[pip.index].switch_index];
|
||||
}
|
||||
|
||||
NetInfo *getConflictingPipNet(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
return switches_locked[chip_info->pip_data[pip.index].switch_index];
|
||||
if (ice40_pip_hard_unavail(pip))
|
||||
return nullptr;
|
||||
|
||||
WireId wire = switches_locked[chip_info->pip_data[pip.index].switch_index];
|
||||
return wire == WireId() ? nullptr : wire_to_net[wire.index];
|
||||
}
|
||||
|
||||
AllPipRange getPips() const
|
||||
|
Loading…
Reference in New Issue
Block a user