timing_opt: Fixes including single-move legality
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
b51308708b
commit
e1c74ad3db
@ -472,6 +472,8 @@ struct Timing
|
|||||||
auto &nd = startdomain.second;
|
auto &nd = startdomain.second;
|
||||||
if (nd.false_startpoint)
|
if (nd.false_startpoint)
|
||||||
continue;
|
continue;
|
||||||
|
if (startdomain.first.clock == async_clock)
|
||||||
|
continue;
|
||||||
const delay_t net_length_plus_one = nd.max_path_length + 1;
|
const delay_t net_length_plus_one = nd.max_path_length + 1;
|
||||||
auto &net_min_remaining_budget = nd.min_remaining_budget;
|
auto &net_min_remaining_budget = nd.min_remaining_budget;
|
||||||
if (nd.min_required.empty())
|
if (nd.min_required.empty())
|
||||||
@ -555,6 +557,8 @@ struct Timing
|
|||||||
const NetInfo *net = net_entry.first;
|
const NetInfo *net = net_entry.first;
|
||||||
for (auto &startdomain : net_entry.second) {
|
for (auto &startdomain : net_entry.second) {
|
||||||
auto &nd = startdomain.second;
|
auto &nd = startdomain.second;
|
||||||
|
if (startdomain.first.clock == async_clock)
|
||||||
|
continue;
|
||||||
if (nd.min_required.empty())
|
if (nd.min_required.empty())
|
||||||
continue;
|
continue;
|
||||||
auto &nc = (*net_crit)[net->name];
|
auto &nc = (*net_crit)[net->name];
|
||||||
@ -575,6 +579,8 @@ struct Timing
|
|||||||
for (auto &net_entry : net_data) {
|
for (auto &net_entry : net_data) {
|
||||||
const NetInfo *net = net_entry.first;
|
const NetInfo *net = net_entry.first;
|
||||||
for (auto &startdomain : net_entry.second) {
|
for (auto &startdomain : net_entry.second) {
|
||||||
|
if (startdomain.first.clock == async_clock)
|
||||||
|
continue;
|
||||||
auto &nd = startdomain.second;
|
auto &nd = startdomain.second;
|
||||||
if (nd.min_required.empty())
|
if (nd.min_required.empty())
|
||||||
continue;
|
continue;
|
||||||
@ -588,7 +594,7 @@ struct Timing
|
|||||||
continue;
|
continue;
|
||||||
delay_t dmax = crit_path->at(ClockPair{startdomain.first, startdomain.first}).path_delay;
|
delay_t dmax = crit_path->at(ClockPair{startdomain.first, startdomain.first}).path_delay;
|
||||||
for (size_t i = 0; i < net->users.size(); i++) {
|
for (size_t i = 0; i < net->users.size(); i++) {
|
||||||
float criticality = 1.0 - ((nc.slack.at(i) - worst_slack.at(startdomain.first)) / dmax);
|
float criticality = 1.0f - (float(nc.slack.at(i) - worst_slack.at(startdomain.first)) / dmax);
|
||||||
nc.criticality.at(i) = std::max(nc.criticality.at(i), criticality);
|
nc.criticality.at(i) = std::max(nc.criticality.at(i), criticality);
|
||||||
}
|
}
|
||||||
nc.max_path_length = std::max(nc.max_path_length, nd.max_path_length);
|
nc.max_path_length = std::max(nc.max_path_length, nd.max_path_length);
|
||||||
|
@ -80,7 +80,7 @@ class TimingOptimiser
|
|||||||
bool optimise() {
|
bool optimise() {
|
||||||
log_info("Running timing-driven placement optimisation...\n");
|
log_info("Running timing-driven placement optimisation...\n");
|
||||||
#if 1
|
#if 1
|
||||||
timing_analysis(ctx, false, true, ctx->debug, false);
|
timing_analysis(ctx, false, true, false, false);
|
||||||
#endif
|
#endif
|
||||||
for (int i = 0; i < 20; i++) {
|
for (int i = 0; i < 20; i++) {
|
||||||
log_info(" Iteration %d...\n", i);
|
log_info(" Iteration %d...\n", i);
|
||||||
@ -90,7 +90,7 @@ class TimingOptimiser
|
|||||||
for (auto &path : crit_paths)
|
for (auto &path : crit_paths)
|
||||||
optimise_path(path);
|
optimise_path(path);
|
||||||
#if 1
|
#if 1
|
||||||
timing_analysis(ctx, false, true, ctx->debug, false);
|
timing_analysis(ctx, false, true, false, false);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -146,8 +146,17 @@ class TimingOptimiser
|
|||||||
if (dstBel == BelId())
|
if (dstBel == BelId())
|
||||||
continue;
|
continue;
|
||||||
if (ctx->estimateDelay(ctx->getBelPinWire(cell->bel, port.first),
|
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)))
|
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
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,6 +202,7 @@ class TimingOptimiser
|
|||||||
BelId curr = cell->bel;
|
BelId curr = cell->bel;
|
||||||
Loc curr_loc = ctx->getBelLocation(curr);
|
Loc curr_loc = ctx->getBelLocation(curr);
|
||||||
int found_count = 0;
|
int found_count = 0;
|
||||||
|
cell_neighbour_bels[cell->name] = std::unordered_set<BelId>{};
|
||||||
for (int dy = -d; dy <= d; dy++) {
|
for (int dy = -d; dy <= d; dy++) {
|
||||||
for (int dx = -d; dx <= d; dx++) {
|
for (int dx = -d; dx <= d; dx++) {
|
||||||
// Go through all the Bels at this location
|
// Go through all the Bels at this location
|
||||||
@ -207,7 +217,7 @@ class TimingOptimiser
|
|||||||
CellInfo *bound = ctx->getBoundBelCell(bel);
|
CellInfo *bound = ctx->getBoundBelCell(bel);
|
||||||
if (bound == nullptr) {
|
if (bound == nullptr) {
|
||||||
free_bels_at_loc.push_back(bel);
|
free_bels_at_loc.push_back(bel);
|
||||||
} else if (bound->belStrength <= STRENGTH_WEAK) {
|
} else if (bound->belStrength <= STRENGTH_WEAK || bound->constr_parent != nullptr || !bound->constr_children.empty()) {
|
||||||
bound_bels_at_loc.push_back(bel);
|
bound_bels_at_loc.push_back(bel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,6 +296,7 @@ class TimingOptimiser
|
|||||||
}
|
}
|
||||||
NPNR_ASSERT_FALSE("port user not found on net");
|
NPNR_ASSERT_FALSE("port user not found on net");
|
||||||
};
|
};
|
||||||
|
std::unordered_set<PortRef*> used_ports;
|
||||||
|
|
||||||
for (auto crit_net : crit_nets) {
|
for (auto crit_net : crit_nets) {
|
||||||
std::deque<PortRef*> crit_path;
|
std::deque<PortRef*> crit_path;
|
||||||
@ -318,6 +329,8 @@ class TimingOptimiser
|
|||||||
continue;
|
continue;
|
||||||
size_t user_idx = port_user_index(cell, port.second);
|
size_t user_idx = port_user_index(cell, port.second);
|
||||||
float usr_crit = net_crit.at(pn->name).criticality.at(user_idx);
|
float usr_crit = net_crit.at(pn->name).criticality.at(user_idx);
|
||||||
|
if (used_ports.count(&(pn->users.at(user_idx))))
|
||||||
|
continue;
|
||||||
if (usr_crit >= max_crit) {
|
if (usr_crit >= max_crit) {
|
||||||
max_crit = usr_crit;
|
max_crit = usr_crit;
|
||||||
crit_sink = std::make_pair(pn, user_idx);
|
crit_sink = std::make_pair(pn, user_idx);
|
||||||
@ -326,6 +339,7 @@ class TimingOptimiser
|
|||||||
|
|
||||||
if (crit_sink.first != nullptr) {
|
if (crit_sink.first != nullptr) {
|
||||||
crit_path.push_front(&(crit_sink.first->users.at(crit_sink.second)));
|
crit_path.push_front(&(crit_sink.first->users.at(crit_sink.second)));
|
||||||
|
used_ports.insert(&(crit_sink.first->users.at(crit_sink.second)));
|
||||||
}
|
}
|
||||||
back_cursor = crit_sink.first;
|
back_cursor = crit_sink.first;
|
||||||
}
|
}
|
||||||
@ -350,14 +364,19 @@ class TimingOptimiser
|
|||||||
if (tpclass != TMG_COMB_OUTPUT)
|
if (tpclass != TMG_COMB_OUTPUT)
|
||||||
continue;
|
continue;
|
||||||
auto &crits = net_crit.at(pn->name).criticality;
|
auto &crits = net_crit.at(pn->name).criticality;
|
||||||
auto most_crit_usr = std::max_element(crits.begin(), crits.end());
|
for (size_t i = 0; i < crits.size(); i++) {
|
||||||
if (*most_crit_usr >= max_crit) {
|
if (used_ports.count(&(pn->users.at(i))))
|
||||||
max_crit = *most_crit_usr;
|
continue;
|
||||||
crit_sink = std::make_pair(pn, std::distance(crits.begin(), most_crit_usr));
|
if (crits.at(i) >= max_crit) {
|
||||||
|
max_crit = crits.at(i);
|
||||||
|
crit_sink = std::make_pair(pn, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (crit_sink.first != nullptr) {
|
if (crit_sink.first != nullptr) {
|
||||||
fwd_cursor = &(crit_sink.first->users.at(crit_sink.second));
|
fwd_cursor = &(crit_sink.first->users.at(crit_sink.second));
|
||||||
|
used_ports.insert(&(crit_sink.first->users.at(crit_sink.second)));
|
||||||
} else {
|
} else {
|
||||||
fwd_cursor = nullptr;
|
fwd_cursor = nullptr;
|
||||||
}
|
}
|
||||||
@ -378,20 +397,30 @@ class TimingOptimiser
|
|||||||
if (ctx->debug)
|
if (ctx->debug)
|
||||||
log_info("Optimising the following path: \n");
|
log_info("Optimising the following path: \n");
|
||||||
for (auto port : path) {
|
for (auto port : path) {
|
||||||
if (ctx->debug)
|
if (ctx->debug) {
|
||||||
log_info(" %s.%s at %s\n", port->cell->name.c_str(ctx), port->port.c_str(ctx), ctx->getBelName(port->cell->bel).c_str(ctx));
|
float crit = 0;
|
||||||
|
NetInfo *pn = port->cell->ports.at(port->port).net;
|
||||||
|
if (net_crit.count(pn->name) && !net_crit.at(pn->name).criticality.empty())
|
||||||
|
for (size_t i = 0; i < pn->users.size(); i++)
|
||||||
|
if (pn->users.at(i).cell == port->cell && pn->users.at(i).port == port->port)
|
||||||
|
crit = net_crit.at(pn->name).criticality.at(i);
|
||||||
|
log_info(" %s.%s at %s crit %0.02f\n", port->cell->name.c_str(ctx), port->port.c_str(ctx), ctx->getBelName(port->cell->bel).c_str(ctx), crit);
|
||||||
|
|
||||||
|
}
|
||||||
if (std::find(path_cells.begin(), path_cells.end(), port->cell->name) != path_cells.end())
|
if (std::find(path_cells.begin(), path_cells.end(), port->cell->name) != path_cells.end())
|
||||||
continue;
|
continue;
|
||||||
if (port->cell->belStrength > STRENGTH_WEAK || !cfg.cellTypes.count(port->cell->type))
|
if (port->cell->belStrength > STRENGTH_WEAK || !cfg.cellTypes.count(port->cell->type) || port->cell->constr_parent != nullptr || !port->cell->constr_children.empty())
|
||||||
continue;
|
continue;
|
||||||
if (ctx->debug)
|
if (ctx->debug)
|
||||||
log_info(" can move\n");
|
log_info(" can move\n");
|
||||||
path_cells.push_back(port->cell->name);
|
path_cells.push_back(port->cell->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path_cells.empty())
|
if (path_cells.size() < 3) {
|
||||||
|
log_info("Too few moveable cells; skipping path\n");
|
||||||
|
log_break();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
IdString last_cell;
|
IdString last_cell;
|
||||||
const int d = 3; // FIXME: how to best determine d
|
const int d = 3; // FIXME: how to best determine d
|
||||||
for (auto cell : path_cells) {
|
for (auto cell : path_cells) {
|
||||||
@ -420,9 +449,17 @@ class TimingOptimiser
|
|||||||
std::unordered_set<std::pair<int, BelId>> to_visit;
|
std::unordered_set<std::pair<int, BelId>> to_visit;
|
||||||
|
|
||||||
for (auto startbel : cell_neighbour_bels[path_cells.front()]) {
|
for (auto startbel : cell_neighbour_bels[path_cells.front()]) {
|
||||||
auto entry = std::make_pair(0, startbel);
|
// Swap for legality check
|
||||||
visit.push(entry);
|
CellInfo *cell = ctx->cells.at(path_cells.front()).get();
|
||||||
cumul_costs[path_cells.front()][startbel] = 0;
|
BelId origBel = cell_swap_bel(cell, startbel);
|
||||||
|
std::vector<std::pair<CellInfo*,BelId>> move{std::make_pair(cell, origBel)};
|
||||||
|
if (acceptable_move(move)) {
|
||||||
|
auto entry = std::make_pair(0, startbel);
|
||||||
|
visit.push(entry);
|
||||||
|
cumul_costs[path_cells.front()][startbel] = 0;
|
||||||
|
}
|
||||||
|
// Swap back
|
||||||
|
cell_swap_bel(cell, origBel);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(!visit.empty()) {
|
while(!visit.empty()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user