router2: further hackery
This commit is contained in:
parent
c9b3c72bff
commit
dc64d32497
@ -589,7 +589,7 @@ struct Router2
|
|||||||
auto &usr = net->users.at(i);
|
auto &usr = net->users.at(i);
|
||||||
ROUTE_LOG_DBG("Routing arc %d of net '%s' (%d, %d) -> (%d, %d)\n", i.idx(), ctx->nameOf(net), ad.bb.x0,
|
ROUTE_LOG_DBG("Routing arc %d of net '%s' (%d, %d) -> (%d, %d)\n", i.idx(), ctx->nameOf(net), ad.bb.x0,
|
||||||
ad.bb.y0, ad.bb.x1, ad.bb.y1);
|
ad.bb.y0, ad.bb.x1, ad.bb.y1);
|
||||||
bool verbose = false; //strcmp(ctx->nameOf(net), "_zz_132__LUT4_A_Z") == 0;
|
bool verbose = false; //strcmp(ctx->nameOf(net), "reset$TRELLIS_IO_IN") == 0;
|
||||||
WireId src_wire = ctx->getNetinfoSourceWire(net), dst_wire = ctx->getNetinfoSinkWire(net, usr, phys_pin);
|
WireId src_wire = ctx->getNetinfoSourceWire(net), dst_wire = ctx->getNetinfoSinkWire(net, usr, phys_pin);
|
||||||
if (src_wire == WireId())
|
if (src_wire == WireId())
|
||||||
ARC_LOG_ERR("No wire found for port %s on source cell %s.\n", ctx->nameOf(net->driver.port),
|
ARC_LOG_ERR("No wire found for port %s on source cell %s.\n", ctx->nameOf(net->driver.port),
|
||||||
@ -607,9 +607,6 @@ struct Router2
|
|||||||
if (t.processed_sinks.count(dst_wire))
|
if (t.processed_sinks.count(dst_wire))
|
||||||
return ARC_SUCCESS;
|
return ARC_SUCCESS;
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
log("awoo\n");
|
|
||||||
|
|
||||||
// Impl note:
|
// Impl note:
|
||||||
// t.fwd_queue = H (i.e. the high priority nodes)
|
// t.fwd_queue = H (i.e. the high priority nodes)
|
||||||
// t.bwd_queue = G (i.e. the unexpanded nodes)
|
// t.bwd_queue = G (i.e. the unexpanded nodes)
|
||||||
@ -627,35 +624,30 @@ struct Router2
|
|||||||
// Unvisit any previously visited wires
|
// Unvisit any previously visited wires
|
||||||
reset_wires(t);
|
reset_wires(t);
|
||||||
|
|
||||||
auto wire_count = [](int x0, int x1) {
|
auto wire_count = [](int x0, int x1, int y0, int y1) {
|
||||||
unsigned int priority = 0;
|
float priority = 0;
|
||||||
auto x = x1 - x0;
|
auto x = x1 - x0;
|
||||||
|
auto y = y1 - y0;
|
||||||
// HACK: ECP5-specific.
|
// HACK: ECP5-specific.
|
||||||
// H6 wires:
|
// H6 wires:
|
||||||
priority += x / 6;
|
/*priority += x / 6;
|
||||||
x -= 6 * (x / 6);
|
x -= 6 * (x / 6);
|
||||||
if (x % 6 == 2 || x % 6 == 4) {
|
if (x % 6 == 2 || x % 6 == 4) {
|
||||||
// Assume an extra H6 is used here.
|
// Assume an extra H6 is used here.
|
||||||
priority++;
|
priority++;
|
||||||
x -= x % 6;
|
x -= x % 6;
|
||||||
}
|
}*/
|
||||||
// H2/H1 wires:
|
// H2/H1 wires:
|
||||||
priority += x / 2;
|
/*if (x % 2 == 1) {
|
||||||
if (x % 2 == 1) {
|
|
||||||
// Assume an extra H2 or H1 is used here.
|
// Assume an extra H2 or H1 is used here.
|
||||||
priority++;
|
priority++;
|
||||||
}
|
}*/
|
||||||
return priority;
|
return unsigned(0.56626506*x + 0.55421686*y);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fast maze search.
|
auto lowest_priority = [&](QueuedWire curr) {
|
||||||
auto fast_search = [&](QueuedWire curr){
|
|
||||||
while (curr.wire != dst_wire_idx) {
|
|
||||||
NPNR_ASSERT(curr.wire < flat_wires.size());
|
|
||||||
auto &curr_data = flat_wires.at(curr.wire);
|
auto &curr_data = flat_wires.at(curr.wire);
|
||||||
|
auto priority = std::numeric_limits<unsigned int>::max();
|
||||||
// Neighbour pass 1: find priorities.
|
|
||||||
auto lowest_priority = std::numeric_limits<unsigned int>::max();
|
|
||||||
for (PipId dh : ctx->getPipsDownhill(curr_data.w)) {
|
for (PipId dh : ctx->getPipsDownhill(curr_data.w)) {
|
||||||
// Skip pips outside of box in bounding-box mode
|
// Skip pips outside of box in bounding-box mode
|
||||||
if (is_bb && !hit_test_pip(nd.bb, ctx->getPipLocation(dh)))
|
if (is_bb && !hit_test_pip(nd.bb, ctx->getPipLocation(dh)))
|
||||||
@ -681,9 +673,30 @@ struct Router2
|
|||||||
if (!thread_test_wire(t, nwd))
|
if (!thread_test_wire(t, nwd))
|
||||||
continue; // thread safety issue
|
continue; // thread safety issue
|
||||||
auto box = ctx->getRouteBoundingBox(ctx->getPipDstWire(dh), dst_wire);
|
auto box = ctx->getRouteBoundingBox(ctx->getPipDstWire(dh), dst_wire);
|
||||||
unsigned int priority = wire_count(box.x0, box.x1) + wire_count(box.y0, box.y1);
|
unsigned int p = wire_count(box.x0, box.x1, box.y0, box.y1);
|
||||||
lowest_priority = std::min(priority, lowest_priority);
|
priority = std::min(p, priority);
|
||||||
}
|
}
|
||||||
|
return priority;
|
||||||
|
};
|
||||||
|
|
||||||
|
dict<PipId, unsigned int> prios;
|
||||||
|
|
||||||
|
// Fast maze search.
|
||||||
|
int nodes = 0;
|
||||||
|
auto fast_search = [&](QueuedWire curr){
|
||||||
|
if (curr.wire == dst_wire_idx) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
while (!done) {
|
||||||
|
NPNR_ASSERT(curr.wire < flat_wires.size());
|
||||||
|
auto &curr_data = flat_wires.at(curr.wire);
|
||||||
|
|
||||||
|
nodes++;
|
||||||
|
|
||||||
|
// Neighbour pass 1: find priorities.
|
||||||
|
auto lowest = lowest_priority(curr);
|
||||||
|
|
||||||
// Neighbour pass 2: add high-priority nodes to the list.
|
// Neighbour pass 2: add high-priority nodes to the list.
|
||||||
for (PipId dh : ctx->getPipsDownhill(curr_data.w)) {
|
for (PipId dh : ctx->getPipsDownhill(curr_data.w)) {
|
||||||
@ -716,8 +729,9 @@ struct Router2
|
|||||||
next_score.togo = get_togo_cost(net, i, next_idx, dst_wire, false, crit_weight);
|
next_score.togo = get_togo_cost(net, i, next_idx, dst_wire, false, crit_weight);
|
||||||
auto qw = QueuedWire(next_idx, next_score, t.rng.rng());
|
auto qw = QueuedWire(next_idx, next_score, t.rng.rng());
|
||||||
auto box = ctx->getRouteBoundingBox(ctx->getPipDstWire(dh), dst_wire);
|
auto box = ctx->getRouteBoundingBox(ctx->getPipDstWire(dh), dst_wire);
|
||||||
unsigned int priority = wire_count(box.x0, box.x1) + wire_count(box.y0, box.y1);
|
unsigned int priority = wire_count(box.x0, box.x1, box.y0, box.y1);
|
||||||
if (priority - lowest_priority == 0) {
|
prios.insert({dh, priority});
|
||||||
|
if (priority - lowest == 0) {
|
||||||
auto& unexplored_best = t.bwd_queue.top();
|
auto& unexplored_best = t.bwd_queue.top();
|
||||||
if (t.bwd_queue.empty() || next_score.total() <= unexplored_best.score.total()) {
|
if (t.bwd_queue.empty() || next_score.total() <= unexplored_best.score.total()) {
|
||||||
t.fwd_queue.push(qw);
|
t.fwd_queue.push(qw);
|
||||||
@ -727,17 +741,27 @@ struct Router2
|
|||||||
} else {
|
} else {
|
||||||
low_prio.push_back(qw);
|
low_prio.push_back(qw);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_visited_fwd(t, next_idx, dh);
|
set_visited_fwd(t, next_idx, dh);
|
||||||
|
|
||||||
|
if (next_idx == dst_wire_idx) {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t.fwd_queue.empty()) {
|
if (t.fwd_queue.empty()) {
|
||||||
return false;
|
break;
|
||||||
} else {
|
} else {
|
||||||
curr = t.fwd_queue.top();
|
curr = t.fwd_queue.top();
|
||||||
t.fwd_queue.pop();
|
t.fwd_queue.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
if (verbose)
|
||||||
|
log(" explored %d nodes\n", nodes);
|
||||||
|
|
||||||
|
return done;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto backtrack = [&](){
|
auto backtrack = [&](){
|
||||||
@ -785,15 +809,78 @@ struct Router2
|
|||||||
next_score.congest = 0.0;
|
next_score.congest = 0.0;
|
||||||
next_score.delay = 0.0;
|
next_score.delay = 0.0;
|
||||||
next_score.togo = get_togo_cost(net, i, src_wire_idx, dst_wire, false, crit_weight);
|
next_score.togo = get_togo_cost(net, i, src_wire_idx, dst_wire, false, crit_weight);
|
||||||
auto curr = QueuedWire(src_wire_idx, next_score, t.rng.rng());
|
auto src_qw = QueuedWire(src_wire_idx, next_score, t.rng.rng());
|
||||||
|
t.fwd_queue.push(src_qw);
|
||||||
|
t.bwd_queue.push(src_qw);
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
while (!t.fwd_queue.empty()) {
|
||||||
|
auto curr = t.fwd_queue.top();
|
||||||
|
t.fwd_queue.pop();
|
||||||
|
auto &curr_data = flat_wires.at(curr.wire);
|
||||||
|
|
||||||
|
nodes++;
|
||||||
|
|
||||||
|
for (PipId dh : ctx->getPipsDownhill(curr_data.w)) {
|
||||||
|
WireId next = ctx->getPipDstWire(dh);
|
||||||
|
int next_idx = wire_to_idx.at(next);
|
||||||
|
// Skip pips outside of box in bounding-box mode
|
||||||
|
if (is_bb && !hit_test_pip(nd.bb, ctx->getPipLocation(dh)))
|
||||||
|
continue;
|
||||||
|
if (!ctx->checkPipAvailForNet(dh, net))
|
||||||
|
continue;
|
||||||
|
if (was_visited_fwd(next_idx))
|
||||||
|
continue;
|
||||||
|
auto &nwd = flat_wires.at(next_idx);
|
||||||
|
if (nwd.unavailable)
|
||||||
|
continue;
|
||||||
|
// Reserved for another net
|
||||||
|
if (nwd.reserved_net != -1 && nwd.reserved_net != net->udata)
|
||||||
|
continue;
|
||||||
|
// Don't allow the same wire to be bound to the same net with a different driving pip
|
||||||
|
auto fnd_wire = nd.wires.find(next);
|
||||||
|
if (fnd_wire != nd.wires.end() && fnd_wire->second.first != dh)
|
||||||
|
continue;
|
||||||
|
if (!thread_test_wire(t, nwd))
|
||||||
|
continue; // thread safety issue
|
||||||
|
|
||||||
|
WireScore next_score;
|
||||||
|
next_score.criticality = crit;
|
||||||
|
next_score.congest = curr.score.congest + score_wire_for_arc_congest(net, i, phys_pin, next, dh, crit_weight);
|
||||||
|
next_score.delay = curr.score.delay + score_wire_for_arc_delay(net, i, phys_pin, next, dh, crit_weight);
|
||||||
|
next_score.togo = get_togo_cost(net, i, next_idx, dst_wire, false, crit_weight);
|
||||||
|
auto qw = QueuedWire(next_idx, next_score, t.rng.rng());
|
||||||
|
|
||||||
|
if (net->wires.find(next) != net->wires.end()) {
|
||||||
|
log("Discovered existing routing wire %s\n", ctx->nameOfWire(next));
|
||||||
|
t.fwd_queue.push(qw);
|
||||||
|
t.bwd_queue.push(qw);
|
||||||
|
} else {
|
||||||
|
t.bwd_queue.push(qw);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_visited_fwd(t, next_idx, dh);
|
||||||
|
|
||||||
|
if (next_idx == dst_wire_idx)
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_calls = 0;
|
||||||
|
int bt_calls = 0;
|
||||||
|
if (!done) {
|
||||||
|
NPNR_ASSERT(!t.bwd_queue.empty());
|
||||||
|
|
||||||
|
auto curr = t.bwd_queue.top();
|
||||||
|
t.bwd_queue.pop();
|
||||||
|
|
||||||
NPNR_ASSERT(curr.wire < flat_wires.size());
|
NPNR_ASSERT(curr.wire < flat_wires.size());
|
||||||
|
|
||||||
bool done = false;
|
|
||||||
int fs_calls = 0;
|
|
||||||
int bt_calls = 0;
|
|
||||||
while (!done) {
|
while (!done) {
|
||||||
fs_calls++;
|
fs_calls++;
|
||||||
|
if (verbose)
|
||||||
|
log("fast_search from %s to %s\n", ctx->nameOfWire(flat_wires.at(curr.wire).w), ctx->nameOfWire(dst_wire));
|
||||||
done = fast_search(curr);
|
done = fast_search(curr);
|
||||||
if (!done) {
|
if (!done) {
|
||||||
if (t.bwd_queue.empty() && low_prio.empty()) {
|
if (t.bwd_queue.empty() && low_prio.empty()) {
|
||||||
@ -801,15 +888,22 @@ struct Router2
|
|||||||
//log("fail; %d fs calls, %d bt calls\n", fs_calls, bt_calls);
|
//log("fail; %d fs calls, %d bt calls\n", fs_calls, bt_calls);
|
||||||
return ARC_RETRY_WITHOUT_BB;
|
return ARC_RETRY_WITHOUT_BB;
|
||||||
} else {
|
} else {
|
||||||
|
if (verbose)
|
||||||
|
log(" failed; backtracking\n");
|
||||||
curr = backtrack();
|
curr = backtrack();
|
||||||
bt_calls++;
|
bt_calls++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int cursor_bwd = dst_wire_idx;
|
int cursor_bwd = dst_wire_idx;
|
||||||
|
int path_prio = 0, path_len = 0;
|
||||||
while (was_visited_fwd(cursor_bwd)) {
|
while (was_visited_fwd(cursor_bwd)) {
|
||||||
PipId pip = flat_wires.at(cursor_bwd).pip_fwd;
|
PipId pip = flat_wires.at(cursor_bwd).pip_fwd;
|
||||||
|
if (prios.find(pip) != prios.end())
|
||||||
|
path_prio += prios.at(pip);
|
||||||
|
path_len++;
|
||||||
if (pip == PipId() && cursor_bwd != src_wire_idx)
|
if (pip == PipId() && cursor_bwd != src_wire_idx)
|
||||||
break;
|
break;
|
||||||
bind_pip_internal(nd, i, cursor_bwd, pip);
|
bind_pip_internal(nd, i, cursor_bwd, pip);
|
||||||
@ -826,8 +920,20 @@ struct Router2
|
|||||||
cursor_bwd = wire_to_idx.at(ctx->getPipSrcWire(pip));
|
cursor_bwd = wire_to_idx.at(ctx->getPipSrcWire(pip));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_wire_by_loc(t, net, i, phys_pin, is_mt);
|
||||||
|
t.processed_sinks.insert(dst_wire);
|
||||||
|
ad.routed = true;
|
||||||
|
|
||||||
reset_wires(t);
|
reset_wires(t);
|
||||||
//log("done; %d fs calls, %d bt calls\n", fs_calls, bt_calls);
|
if (verbose)
|
||||||
|
log("done; %d fs calls, %d bt calls\n", fs_calls, bt_calls);
|
||||||
|
|
||||||
|
auto arc_end = std::chrono::high_resolution_clock::now();
|
||||||
|
auto box = ctx->getRouteBoundingBox(src_wire, dst_wire);
|
||||||
|
//printf("%d,%d,%f,%d\n", box.x1 - box.x0, box.y1 - box.y0, crit, path_len);
|
||||||
|
if (verbose)
|
||||||
|
log("Routing arc %d of net '%s' (is_bb = %d) took %02fs; path: %.03f/%d/%d/%d nodes\n", i.idx(), ctx->nameOf(net), is_bb,
|
||||||
|
std::chrono::duration<float>(arc_end - arc_start).count(), float(path_prio)/float(path_len), lowest_priority(src_qw), path_len, nodes);
|
||||||
|
|
||||||
return ARC_SUCCESS;
|
return ARC_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -1703,6 +1809,23 @@ struct Router2
|
|||||||
++iter;
|
++iter;
|
||||||
if (curr_cong_weight < 1e9)
|
if (curr_cong_weight < 1e9)
|
||||||
curr_cong_weight += cfg.curr_cong_mult;
|
curr_cong_weight += cfg.curr_cong_mult;
|
||||||
|
|
||||||
|
if (cfg.perf_profile) {
|
||||||
|
std::vector<std::pair<int, IdString>> nets_by_runtime;
|
||||||
|
for (auto &n : nets_by_udata) {
|
||||||
|
nets_by_runtime.emplace_back(nets.at(n->udata).total_route_us, n->name);
|
||||||
|
}
|
||||||
|
std::sort(nets_by_runtime.begin(), nets_by_runtime.end(), std::greater<std::pair<int, IdString>>());
|
||||||
|
log_info("100 slowest nets by runtime:\n");
|
||||||
|
for (int i = 0; i < std::min(int(nets_by_runtime.size()), 100); i++) {
|
||||||
|
if (nets_by_runtime.at(i).first < 1000000.0)
|
||||||
|
break;
|
||||||
|
log(" %80s %6d %.1fms\n", nets_by_runtime.at(i).second.c_str(ctx),
|
||||||
|
int(ctx->nets.at(nets_by_runtime.at(i).second)->users.entries()),
|
||||||
|
nets_by_runtime.at(i).first / 1000.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tmg.print_fmax();
|
tmg.print_fmax();
|
||||||
} while (!failed_nets.empty());
|
} while (!failed_nets.empty());
|
||||||
if (cfg.perf_profile) {
|
if (cfg.perf_profile) {
|
||||||
@ -1749,7 +1872,7 @@ Router2Cfg::Router2Cfg(Context *ctx)
|
|||||||
hist_cong_weight = ctx->setting<float>("router2/histCongWeight", 1.0f);
|
hist_cong_weight = ctx->setting<float>("router2/histCongWeight", 1.0f);
|
||||||
curr_cong_mult = ctx->setting<float>("router2/currCongWeightMult", 2.0f);
|
curr_cong_mult = ctx->setting<float>("router2/currCongWeightMult", 2.0f);
|
||||||
estimate_weight = ctx->setting<float>("router2/estimateWeight", 1.25f);
|
estimate_weight = ctx->setting<float>("router2/estimateWeight", 1.25f);
|
||||||
perf_profile = ctx->setting<bool>("router2/perfProfile", false);
|
perf_profile = ctx->setting<bool>("router2/perfProfile", true);
|
||||||
if (ctx->settings.count(ctx->id("router2/heatmap")))
|
if (ctx->settings.count(ctx->id("router2/heatmap")))
|
||||||
heatmap = ctx->settings.at(ctx->id("router2/heatmap")).as_string();
|
heatmap = ctx->settings.at(ctx->id("router2/heatmap")).as_string();
|
||||||
else
|
else
|
||||||
|
Loading…
Reference in New Issue
Block a user