diff --git a/common/kernel/command.cc b/common/kernel/command.cc index 43eb491af2..86940c5465 100644 --- a/common/kernel/command.cc +++ b/common/kernel/command.cc @@ -345,7 +345,9 @@ po::options_description CommandHandler::getGeneralOptions() general.add_options()("top", po::value(), "name of top module"); general.add_options()("seed", po::value(), "seed value for random number generator"); general.add_options()("randomize-seed,r", "randomize seed value for random number generator"); - + general.add_options()("restart-on-failed-target-frequency", + "restart place and route if target frequency is not achieved (use together with " + "--randomize-seed option)"); general.add_options()( "placer", po::value(), std::string("placer algorithm to use; available: " + boost::algorithm::join(Arch::availablePlacers, ", ") + @@ -673,6 +675,17 @@ int CommandHandler::executeMain(std::unique_ptr ctx) ctx->debug = true; if (!ctx->place() && !ctx->force) log_error("Placing design failed.\n"); + if (vm.count("restart-on-failed-target-frequency")) { + if (!ctx->target_frequency_achieved) { + log_break(); + log_info("Target frequency not achieved, restarting...\n"); + log_break(); +#ifndef NO_PYTHON + deinit_python(); +#endif + return 2; + } + } ctx->debug = saved_debug; ctx->check(); if (vm.count("placed-svg")) @@ -686,6 +699,17 @@ int CommandHandler::executeMain(std::unique_ptr ctx) ctx->debug = true; if (!ctx->route() && !ctx->force) log_error("Routing design failed.\n"); + if (vm.count("restart-on-failed-target-frequency")) { + if (!ctx->target_frequency_achieved) { + log_break(); + log_info("Target frequency not achieved, restarting...\n"); + log_break(); +#ifndef NO_PYTHON + deinit_python(); +#endif + return 2; + } + } ctx->debug = saved_debug; run_script_hook("post-route"); if (vm.count("routed-svg")) @@ -753,10 +777,15 @@ int CommandHandler::exec() return 0; dict values; +restart: std::unique_ptr ctx = createContext(values); setupContext(ctx.get()); setupArchContext(ctx.get()); int rc = executeMain(std::move(ctx)); + if (rc == 2) { + ctx.reset(); + goto restart; + } printFooter(); log_break(); log_info("Program finished normally.\n"); diff --git a/common/kernel/context.h b/common/kernel/context.h index bd50e81791..09162958e4 100644 --- a/common/kernel/context.h +++ b/common/kernel/context.h @@ -38,6 +38,8 @@ struct Context : Arch, DeterministicRNG bool disable_critical_path_source_print = false; // True when detailed per-net timing is to be stored / reported bool detailed_timing_report = false; + // Default to true, will update when timing analysis is run + bool target_frequency_achieved = true; ArchArgs arch_args; diff --git a/common/kernel/timing.cc b/common/kernel/timing.cc index 880cc50691..6d5c18ee71 100644 --- a/common/kernel/timing.cc +++ b/common/kernel/timing.cc @@ -1339,6 +1339,16 @@ void timing_analysis(Context *ctx, bool print_slack_histogram, bool print_fmax, if (update_results) ctx->timing_result = result; + + ctx->target_frequency_achieved = true; + for (auto &clock : result.clock_paths) { + float fmax = result.clock_fmax[clock.first].achieved; + float target = result.clock_fmax[clock.first].constraint; + bool passed = target < fmax; + if (!passed) { + ctx->target_frequency_achieved = false; + } + } } NEXTPNR_NAMESPACE_END diff --git a/common/kernel/timing_log.cc b/common/kernel/timing_log.cc index d0dd8986ba..df72ed62cc 100644 --- a/common/kernel/timing_log.cc +++ b/common/kernel/timing_log.cc @@ -38,35 +38,36 @@ static std::string clock_event_name(const Context *ctx, const ClockEvent &e, int return value; }; -static void log_crit_paths(const Context *ctx, TimingResult &result) +static void print_net_source(const Context *ctx, const NetInfo *net) { - static auto print_net_source = [ctx](const NetInfo *net) { - // Check if this net is annotated with a source list - auto sources = net->attrs.find(ctx->id("src")); - if (sources == net->attrs.end()) { - // No sources for this net, can't print anything - return; - } + // Check if this net is annotated with a source list + auto sources = net->attrs.find(ctx->id("src")); + if (sources == net->attrs.end()) { + // No sources for this net, can't print anything + return; + } - // Sources are separated by pipe characters. - // There is no guaranteed ordering on sources, so we just print all - auto sourcelist = sources->second.as_string(); - std::vector source_entries; - size_t current = 0, prev = 0; - while ((current = sourcelist.find("|", prev)) != std::string::npos) { - source_entries.emplace_back(sourcelist.substr(prev, current - prev)); - prev = current + 1; - } - // Ensure we emplace the final entry + // Sources are separated by pipe characters. + // There is no guaranteed ordering on sources, so we just print all + auto sourcelist = sources->second.as_string(); + std::vector source_entries; + size_t current = 0, prev = 0; + while ((current = sourcelist.find("|", prev)) != std::string::npos) { source_entries.emplace_back(sourcelist.substr(prev, current - prev)); + prev = current + 1; + } + // Ensure we emplace the final entry + source_entries.emplace_back(sourcelist.substr(prev, current - prev)); - // Iterate and print our source list at the correct indentation level - log_info(" Defined in:\n"); - for (auto entry : source_entries) { - log_info(" %s\n", entry.c_str()); - } - }; + // Iterate and print our source list at the correct indentation level + log_info(" Defined in:\n"); + for (auto entry : source_entries) { + log_info(" %s\n", entry.c_str()); + } +} +static void log_crit_paths(const Context *ctx, TimingResult &result) +{ // A helper function for reporting one critical path auto print_path_report = [ctx](const CriticalPath &path) { delay_t total(0), logic_total(0), route_total(0); @@ -137,7 +138,7 @@ static void log_crit_paths(const Context *ctx, TimingResult &result) } if (!ctx->disable_critical_path_source_print) { - print_net_source(net); + print_net_source(ctx, net); } } }