timing_opt: Improve heuristics
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
a990a1576c
commit
f53dc8d3c9
@ -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;
|
||||
}
|
||||
|
@ -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)))
|
||||
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);
|
||||
|
@ -22,7 +22,7 @@ for i in range(num_runs):
|
||||
ascfile = "picorv32_work/picorv32_s{}.asc".format(run)
|
||||
if path.exists(ascfile):
|
||||
os.remove(ascfile)
|
||||
result = subprocess.run(["../nextpnr-ice40", "--hx8k", "--seed", str(run), "--json", "picorv32.json", "--asc", ascfile, "--freq", "70"], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
|
||||
result = subprocess.run(["../nextpnr-ice40", "--hx8k", "--seed", str(run), "--json", "picorv32.json", "--asc", ascfile, "--freq", "40", "--opt-timing"], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
|
||||
if result.returncode != 0:
|
||||
print("Run {} failed!".format(run))
|
||||
else:
|
||||
|
Loading…
Reference in New Issue
Block a user