ecp5: Compute derived constraints iteratively

Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
David Shah 2019-02-22 12:25:34 +00:00
parent 0bc88e622c
commit ab50a6ef54

View File

@ -2154,6 +2154,12 @@ class Ecp5Packer
auto equals_epsilon = [](delay_t a, delay_t b) { return (std::abs(a - b) / std::max(double(b), 1.0)) < 1e-3; }; auto equals_epsilon = [](delay_t a, delay_t b) { return (std::abs(a - b) / std::max(double(b), 1.0)) < 1e-3; };
std::unordered_set<IdString> user_constrained, changed_nets;
for (auto &net : ctx->nets) {
if (net.second->clkconstr != nullptr)
user_constrained.insert(net.first);
changed_nets.insert(net.first);
}
auto get_period = [&](CellInfo *ci, IdString port, delay_t &period) { auto get_period = [&](CellInfo *ci, IdString port, delay_t &period) {
if (!ci->ports.count(port)) if (!ci->ports.count(port))
return false; return false;
@ -2170,8 +2176,10 @@ class Ecp5Packer
NetInfo *to = ci->ports.at(port).net; NetInfo *to = ci->ports.at(port).net;
if (to == nullptr) if (to == nullptr)
return; return;
if (to->clkconstr != nullptr && !equals_epsilon(to->clkconstr->period.min_delay, period)) { if (to->clkconstr != nullptr) {
log_warning(" Overriding derived constraint of %.1f on net %s with user-specified constraint of " if (!equals_epsilon(to->clkconstr->period.min_delay, period) && user_constrained.count(to->name))
log_warning(
" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
"%.1f MHz.\n", "%.1f MHz.\n",
MHz(to->clkconstr->period.min_delay), to->name.c_str(ctx), MHz(period)); MHz(to->clkconstr->period.min_delay), to->name.c_str(ctx), MHz(period));
return; return;
@ -2185,6 +2193,7 @@ class Ecp5Packer
to->clkconstr->period.max_delay = period; to->clkconstr->period.max_delay = period;
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay), log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay),
to->name.c_str(ctx)); to->name.c_str(ctx));
changed_nets.insert(to->name);
}; };
auto copy_constraint = [&](CellInfo *ci, IdString fromPort, IdString toPort, double ratio = 1.0) { auto copy_constraint = [&](CellInfo *ci, IdString fromPort, IdString toPort, double ratio = 1.0) {
@ -2193,9 +2202,12 @@ class Ecp5Packer
NetInfo *from = ci->ports.at(fromPort).net, *to = ci->ports.at(toPort).net; NetInfo *from = ci->ports.at(fromPort).net, *to = ci->ports.at(toPort).net;
if (from == nullptr || from->clkconstr == nullptr || to == nullptr) if (from == nullptr || from->clkconstr == nullptr || to == nullptr)
return; return;
if (to->clkconstr != nullptr && if (to->clkconstr != nullptr) {
!equals_epsilon(to->clkconstr->period.min_delay, delay_t(from->clkconstr->period.min_delay / ratio))) { if (!equals_epsilon(to->clkconstr->period.min_delay,
log_warning(" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of " delay_t(from->clkconstr->period.min_delay / ratio)) &&
user_constrained.count(to->name))
log_warning(
" Overriding derived constraint of %.1f MHz on net %s with user-specified constraint of "
"%.1f MHz.\n", "%.1f MHz.\n",
MHz(to->clkconstr->period.min_delay), to->name.c_str(ctx), MHz(to->clkconstr->period.min_delay), to->name.c_str(ctx),
MHz(delay_t(from->clkconstr->period.min_delay / ratio))); MHz(delay_t(from->clkconstr->period.min_delay / ratio)));
@ -2207,10 +2219,23 @@ class Ecp5Packer
to->clkconstr->period = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->period.min_delay) / ratio); to->clkconstr->period = ctx->getDelayFromNS(ctx->getDelayNS(from->clkconstr->period.min_delay) / ratio);
log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay), log_info(" Derived frequency constraint of %.1f MHz for net %s\n", MHz(to->clkconstr->period.min_delay),
to->name.c_str(ctx)); to->name.c_str(ctx));
changed_nets.insert(to->name);
}; };
for (auto cell : sorted(ctx->cells)) { // Run in a loop while constraints are changing to deal with dependencies
CellInfo *ci = cell.second; // Iteration limit avoids hanging in crazy loopback situation (self-fed PLLs or dividers, etc)
int iter = 0;
const int itermax = 5000;
while (!changed_nets.empty() && iter < itermax) {
++iter;
std::unordered_set<IdString> changed_cells;
for (auto net : changed_nets)
for (auto &user : ctx->nets.at(net)->users)
if (user.port == id_CLKI || user.port == id_ECLKI)
changed_cells.insert(user.cell->name);
changed_nets.clear();
for (auto cell : sorted(changed_cells)) {
CellInfo *ci = ctx->cells.at(cell).get();
if (ci->type == id_CLKDIVF) { if (ci->type == id_CLKDIVF) {
std::string div = str_or_default(ci->params, ctx->id("DIV"), "2.0"); std::string div = str_or_default(ci->params, ctx->id("DIV"), "2.0");
double ratio; double ratio;
@ -2248,7 +2273,8 @@ class Ecp5Packer
double vco_period = period_in_div / feedback_div; double vco_period = period_in_div / feedback_div;
double vco_freq = MHz(vco_period); double vco_freq = MHz(vco_period);
if (vco_freq < 400 || vco_freq > 800) if (vco_freq < 400 || vco_freq > 800)
log_info(" Derived VCO frequency %.1f MHz of PLL '%s' is out of legal range [400MHz, 800MHz]\n", log_info(" Derived VCO frequency %.1f MHz of PLL '%s' is out of legal range [400MHz, "
"800MHz]\n",
vco_freq, ci->name.c_str(ctx)); vco_freq, ci->name.c_str(ctx));
set_period(ci, id_CLKOP, vco_period * int_or_default(ci->params, ctx->id("CLKOP_DIV"), 1)); set_period(ci, id_CLKOP, vco_period * int_or_default(ci->params, ctx->id("CLKOP_DIV"), 1));
set_period(ci, id_CLKOS, vco_period * int_or_default(ci->params, ctx->id("CLKOS_DIV"), 1)); set_period(ci, id_CLKOS, vco_period * int_or_default(ci->params, ctx->id("CLKOS_DIV"), 1));
@ -2260,6 +2286,7 @@ class Ecp5Packer
} }
} }
} }
}
public: public:
void pack() void pack()