aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2018-12-02 15:49:24 +0000
committerDavid Shah <dave@ds0.me>2018-12-06 10:53:01 +0000
commitf53dc8d3c9735b4d9c50db1848de9dd3fefbe7ef (patch)
tree538924ac118afb846ba76f7af01c20919a36a489 /common
parenta990a1576cc3b932ec784a0d9863f0ba9c337b0f (diff)
downloadnextpnr-f53dc8d3c9735b4d9c50db1848de9dd3fefbe7ef.tar.gz
nextpnr-f53dc8d3c9735b4d9c50db1848de9dd3fefbe7ef.tar.bz2
nextpnr-f53dc8d3c9735b4d9c50db1848de9dd3fefbe7ef.zip
timing_opt: Improve heuristics
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'common')
-rw-r--r--common/timing.cc7
-rw-r--r--common/timing_opt.cc63
2 files changed, 49 insertions, 21 deletions
diff --git a/common/timing.cc b/common/timing.cc
index 18caa989..6965307d 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -566,16 +566,20 @@ struct Timing
auto &nc = (*net_crit)[net->name];
if (nc.slack.empty())
nc.slack.resize(net->users.size(), std::numeric_limits<delay_t>::max());
+#if 0
if (ctx->debug)
log_info("Net %s cd %s\n", net->name.c_str(ctx), startdomain.first.clock.c_str(ctx));
+#endif
for (size_t i = 0; i < net->users.size(); i++) {
delay_t slack = nd.min_required.at(i) -
(nd.max_arrival + ctx->getNetinfoRouteDelay(net, net->users.at(i)));
+#if 0
if (ctx->debug)
log_info(" user %s.%s required %.02fns arrival %.02f route %.02f slack %.02f\n",
net->users.at(i).cell->name.c_str(ctx), net->users.at(i).port.c_str(ctx),
ctx->getDelayNS(nd.min_required.at(i)), ctx->getDelayNS(nd.max_arrival),
ctx->getDelayNS(ctx->getNetinfoRouteDelay(net, net->users.at(i))), ctx->getDelayNS(slack));
+#endif
if (worst_slack.count(startdomain.first))
worst_slack.at(startdomain.first) = std::min(worst_slack.at(startdomain.first), slack);
else
@@ -612,7 +616,7 @@ struct Timing
nc.cd_worst_slack = std::min(nc.cd_worst_slack, worst_slack.at(startdomain.first));
}
}
-
+#if 0
if (ctx->debug) {
for (auto &nc : *net_crit) {
NetInfo *net = ctx->nets.at(nc.first).get();
@@ -628,6 +632,7 @@ struct Timing
log_break();
}
}
+#endif
}
return min_slack;
}
diff --git a/common/timing_opt.cc b/common/timing_opt.cc
index ed1618da..e8bb7d4f 100644
--- a/common/timing_opt.cc
+++ b/common/timing_opt.cc
@@ -90,7 +90,7 @@ class TimingOptimiser
log_info(" Iteration %d...\n", i);
get_criticalities(ctx, &net_crit);
setup_delay_limits();
- auto crit_paths = find_crit_paths(0.95, 1000);
+ auto crit_paths = find_crit_paths(0.98, 1000);
for (auto &path : crit_paths)
optimise_path(path);
#if 1
@@ -140,27 +140,23 @@ class TimingOptimiser
if (port.second.type == PORT_IN) {
if (net->driver.cell == nullptr || net->driver.cell->bel == BelId())
continue;
- BelId srcBel = net->driver.cell->bel;
- if (ctx->estimateDelay(ctx->getBelPinWire(srcBel, net->driver.port),
- ctx->getBelPinWire(cell->bel, port.first)) >
- max_net_delay.at(std::make_pair(cell->name, port.first)))
- return false;
+ for (auto user : net->users) {
+ if (user.cell == cell && user.port == port.first) {
+ if (ctx->predictDelay(net, user) >
+ 1.1 * max_net_delay.at(std::make_pair(cell->name, port.first)))
+ return false;
+ }
+ }
+
} else if (port.second.type == PORT_OUT) {
for (auto user : net->users) {
// This could get expensive for high-fanout nets??
BelId dstBel = user.cell->bel;
if (dstBel == BelId())
continue;
- if (ctx->estimateDelay(ctx->getBelPinWire(cell->bel, port.first),
- ctx->getBelPinWire(dstBel, user.port)) >
- max_net_delay.at(std::make_pair(user.cell->name, user.port))) {
-#if 0
- if (ctx->debug) {
- log_info(" est delay %.02fns exceeded maximum %.02fns\n", ctx->getDelayNS(ctx->estimateDelay(ctx->getBelPinWire(cell->bel, port.first),
- ctx->getBelPinWire(dstBel, user.port))),
- ctx->getDelayNS(max_net_delay.at(std::make_pair(user.cell->name, user.port))));
- }
-#endif
+ if (ctx->predictDelay(net, user) >
+ 1.1 * max_net_delay.at(std::make_pair(user.cell->name, user.port))) {
+
return false;
}
}
@@ -370,7 +366,7 @@ class TimingOptimiser
int ccount;
DelayInfo combDelay;
TimingPortClass tpclass = ctx->getPortTimingClass(cell, port.first, ccount);
- if (tpclass != TMG_COMB_OUTPUT)
+ if (tpclass != TMG_COMB_OUTPUT && tpclass != TMG_REGISTER_OUTPUT)
continue;
bool is_path = ctx->getCellDelay(cell, fwd_cursor->port, port.first, combDelay);
if (!is_path)
@@ -408,6 +404,17 @@ class TimingOptimiser
bel_candidate_cells.clear();
if (ctx->debug)
log_info("Optimising the following path: \n");
+
+ auto front_port = path.front();
+ NetInfo *front_net = front_port->cell->ports.at(front_port->port).net;
+ if (front_net != nullptr && front_net->driver.cell != nullptr) {
+ auto front_cell = front_net->driver.cell;
+ if (front_cell->belStrength <= STRENGTH_WEAK && cfg.cellTypes.count(front_cell->type) &&
+ front_cell->constr_parent == nullptr && front_cell->constr_children.empty()) {
+ path_cells.push_back(front_cell->name);
+ }
+ }
+
for (auto port : path) {
if (ctx->debug) {
float crit = 0;
@@ -429,7 +436,7 @@ class TimingOptimiser
path_cells.push_back(port->cell->name);
}
- if (path_cells.size() < 3) {
+ if (path_cells.size() < 2) {
if (ctx->debug) {
log_info("Too few moveable cells; skipping path\n");
log_break();
@@ -437,8 +444,23 @@ class TimingOptimiser
return;
}
+
+ // Calculate original delay before touching anything
+ delay_t original_delay = 0;
+
+ for (size_t i = 0; i < path.size(); i++) {
+ NetInfo *pn = path.at(i)->cell->ports.at(path.at(i)->port).net;
+ for (size_t j = 0; j < pn->users.size(); j++) {
+ auto & usr = pn->users.at(j);
+ if (usr.cell == path.at(i)->cell && usr.port == path.at(i)->port) {
+ original_delay += ctx->predictDelay(pn, usr);
+ break;
+ }
+ }
+ }
+
IdString last_cell;
- const int d = 4; // FIXME: how to best determine d
+ const int d = 3; // FIXME: how to best determine d
for (auto cell : path_cells) {
// FIXME: when should we allow swapping due to a lack of candidates
find_neighbours(ctx->cells[cell].get(), last_cell, d, false);
@@ -556,7 +578,8 @@ class TimingOptimiser
route_to_solution.push_back(cursor);
}
if (ctx->debug)
- log_info("Found a solution with cost %.02f ns\n", ctx->getDelayNS(lowest->second));
+ log_info("Found a solution with cost %.02f ns (existing path %.02f ns)\n", ctx->getDelayNS(lowest->second),
+ ctx->getDelayNS(original_delay));
for (auto rt_entry : boost::adaptors::reverse(route_to_solution)) {
CellInfo *cell = ctx->cells.at(rt_entry.first).get();
cell_swap_bel(cell, rt_entry.second);