diff --git a/common/placer1.cc b/common/placer1.cc index 30f0057c..d38cdd4b 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -276,6 +276,7 @@ class SAPlacer } } } + log_info("estimated Fmax = %.2f MHz\n", compute_fmax(ctx) / 1e6); ctx->unlock(); return true; } diff --git a/common/router1.cc b/common/router1.cc index dbf97af7..8664819f 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -815,6 +815,7 @@ bool router1(Context *ctx) ctx->check(); ctx->unlock(); #endif + log_info("estimated Fmax = %.2f MHz\n", compute_fmax(ctx) / 1e6); return true; } catch (log_execution_error_exception) { #ifndef NDEBUG diff --git a/common/timing.cc b/common/timing.cc index 2c467961..784952f8 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -76,10 +76,35 @@ static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, delay_t s return net_budget; } -void assign_budget(Context *ctx) +static UpdateMap compute_min_slack(Context *ctx, delay_t &min_slack) { UpdateMap updates; - delay_t min_slack = delay_t(1.0e12 / ctx->target_freq); + delay_t default_slack = delay_t(1.0e12 / ctx->target_freq); + + // Go through all clocked drivers and distribute the available path + // slack evenly into the budget of every sink on the path --- + // record this value into the UpdateMap + for (auto &cell : ctx->cells) { + for (auto port : cell.second->ports) { + if (port.second.type == PORT_OUT) { + IdString clock_domain = ctx->getPortClock(cell.second.get(), port.first); + if (clock_domain != IdString()) { + delay_t slack = default_slack; // TODO: clock constraints + delay_t clkToQ; + if (ctx->getCellDelay(cell.second.get(), clock_domain, port.first, clkToQ)) + slack -= clkToQ; + if (port.second.net) + follow_net(ctx, port.second.net, 0, slack, updates, min_slack); + } + } + } + } + + return updates; +} + +void assign_budget(Context *ctx) +{ log_break(); log_info("Annotating ports with timing budgets\n"); @@ -90,26 +115,12 @@ void assign_budget(Context *ctx) usr.budget = default_slack; } } - min_slack = default_slack; - // Go through all clocked drivers and set up paths - for (auto &cell : ctx->cells) { - for (auto port : cell.second->ports) { - if (port.second.type == PORT_OUT) { - IdString clock_domain = ctx->getPortClock(cell.second.get(), port.first); - if (clock_domain != IdString()) { - delay_t slack = delay_t(1.0e12 / ctx->target_freq); // TODO: clock constraints - delay_t clkToQ; - if (ctx->getCellDelay(cell.second.get(), clock_domain, port.first, clkToQ)) - slack -= clkToQ; - if (port.second.net) { - log_break(); - follow_net(ctx, port.second.net, 0, slack, updates, min_slack); - } - } - } - } - } + delay_t min_slack = default_slack; + auto updates = compute_min_slack(ctx, min_slack); + + // If user has not specified a frequency, adjust the target frequency + // to be equivalent to the critical path if (!ctx->user_freq) { ctx->target_freq = 1e12 / (default_slack - min_slack); if (ctx->verbose) @@ -145,27 +156,12 @@ void assign_budget(Context *ctx) void update_budget(Context *ctx) { - UpdateMap updates; delay_t default_slack = delay_t(1.0e12 / ctx->target_freq); - delay_t min_slack = delay_t(1.0e12 / ctx->target_freq); - - // Go through all clocked drivers and distribute the available path slack evenly into every budget - for (auto &cell : ctx->cells) { - for (auto& port : cell.second->ports) { - if (port.second.type == PORT_OUT) { - IdString clock_domain = ctx->getPortClock(cell.second.get(), port.first); - if (clock_domain != IdString()) { - delay_t slack = default_slack; // TODO: clock constraints - delay_t clkToQ; - if (ctx->getCellDelay(cell.second.get(), clock_domain, port.first, clkToQ)) - slack -= clkToQ; - if (port.second.net) - follow_net(ctx, port.second.net, 0, slack, updates, min_slack); - } - } - } - } + delay_t min_slack = default_slack; + auto updates = compute_min_slack(ctx, min_slack); + // If user has not specified a frequency, adjust the target frequency + // to be +5% higher than the current critical path if (!ctx->user_freq) { ctx->target_freq = 1.05 * (1e12 / (default_slack - min_slack)); if (ctx->verbose) @@ -199,4 +195,12 @@ void update_budget(Context *ctx) } } +float compute_fmax(Context *ctx) +{ + delay_t default_slack = delay_t(1.0e12 / ctx->target_freq); + delay_t min_slack = default_slack; + compute_min_slack(ctx, min_slack); + return 1e12 / (default_slack - min_slack); +} + NEXTPNR_NAMESPACE_END diff --git a/common/timing.h b/common/timing.h index b5574392..22aa40c7 100644 --- a/common/timing.h +++ b/common/timing.h @@ -27,8 +27,11 @@ NEXTPNR_NAMESPACE_BEGIN // Assign "budget" values for all user ports in the design void assign_budget(Context *ctx); +// Evenly redistribute the total path slack amongst all sinks on each path void update_budget(Context *ctx); +float compute_fmax(Context *ctx); + NEXTPNR_NAMESPACE_END #endif