Add flag to restart place-and-route on failed target frequency
* Add --restart-on-failed-target-frequency flag and logic to restart the place-and-route process if the target frequency is not achieved. * This flag is intended to be used with the --randomize-seed option to generate a new random seed for every run. This can significantly improve the chances of achieving a higher clock frequency compared to using the default seed. * Move print_net_source out of log_crit_paths() to remove the 'static' keyword, which could otherwise cause a segmentation fault if the context is changed.
This commit is contained in:
parent
437fb70ed3
commit
a0356aa0fc
@ -345,7 +345,9 @@ po::options_description CommandHandler::getGeneralOptions()
|
|||||||
general.add_options()("top", po::value<std::string>(), "name of top module");
|
general.add_options()("top", po::value<std::string>(), "name of top module");
|
||||||
general.add_options()("seed", po::value<uint64_t>(), "seed value for random number generator");
|
general.add_options()("seed", po::value<uint64_t>(), "seed value for random number generator");
|
||||||
general.add_options()("randomize-seed,r", "randomize 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()(
|
general.add_options()(
|
||||||
"placer", po::value<std::string>(),
|
"placer", po::value<std::string>(),
|
||||||
std::string("placer algorithm to use; available: " + boost::algorithm::join(Arch::availablePlacers, ", ") +
|
std::string("placer algorithm to use; available: " + boost::algorithm::join(Arch::availablePlacers, ", ") +
|
||||||
@ -673,6 +675,17 @@ int CommandHandler::executeMain(std::unique_ptr<Context> ctx)
|
|||||||
ctx->debug = true;
|
ctx->debug = true;
|
||||||
if (!ctx->place() && !ctx->force)
|
if (!ctx->place() && !ctx->force)
|
||||||
log_error("Placing design failed.\n");
|
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->debug = saved_debug;
|
||||||
ctx->check();
|
ctx->check();
|
||||||
if (vm.count("placed-svg"))
|
if (vm.count("placed-svg"))
|
||||||
@ -686,6 +699,17 @@ int CommandHandler::executeMain(std::unique_ptr<Context> ctx)
|
|||||||
ctx->debug = true;
|
ctx->debug = true;
|
||||||
if (!ctx->route() && !ctx->force)
|
if (!ctx->route() && !ctx->force)
|
||||||
log_error("Routing design failed.\n");
|
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;
|
ctx->debug = saved_debug;
|
||||||
run_script_hook("post-route");
|
run_script_hook("post-route");
|
||||||
if (vm.count("routed-svg"))
|
if (vm.count("routed-svg"))
|
||||||
@ -753,10 +777,15 @@ int CommandHandler::exec()
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dict<std::string, Property> values;
|
dict<std::string, Property> values;
|
||||||
|
restart:
|
||||||
std::unique_ptr<Context> ctx = createContext(values);
|
std::unique_ptr<Context> ctx = createContext(values);
|
||||||
setupContext(ctx.get());
|
setupContext(ctx.get());
|
||||||
setupArchContext(ctx.get());
|
setupArchContext(ctx.get());
|
||||||
int rc = executeMain(std::move(ctx));
|
int rc = executeMain(std::move(ctx));
|
||||||
|
if (rc == 2) {
|
||||||
|
ctx.reset();
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
printFooter();
|
printFooter();
|
||||||
log_break();
|
log_break();
|
||||||
log_info("Program finished normally.\n");
|
log_info("Program finished normally.\n");
|
||||||
|
@ -38,6 +38,8 @@ struct Context : Arch, DeterministicRNG
|
|||||||
bool disable_critical_path_source_print = false;
|
bool disable_critical_path_source_print = false;
|
||||||
// True when detailed per-net timing is to be stored / reported
|
// True when detailed per-net timing is to be stored / reported
|
||||||
bool detailed_timing_report = false;
|
bool detailed_timing_report = false;
|
||||||
|
// Default to true, will update when timing analysis is run
|
||||||
|
bool target_frequency_achieved = true;
|
||||||
|
|
||||||
ArchArgs arch_args;
|
ArchArgs arch_args;
|
||||||
|
|
||||||
|
@ -1339,6 +1339,16 @@ void timing_analysis(Context *ctx, bool print_slack_histogram, bool print_fmax,
|
|||||||
|
|
||||||
if (update_results)
|
if (update_results)
|
||||||
ctx->timing_result = result;
|
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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -38,35 +38,36 @@ static std::string clock_event_name(const Context *ctx, const ClockEvent &e, int
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void print_net_source(const Context *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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<std::string> 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void log_crit_paths(const Context *ctx, TimingResult &result)
|
static void log_crit_paths(const Context *ctx, TimingResult &result)
|
||||||
{
|
{
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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<std::string> 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());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// A helper function for reporting one critical path
|
// A helper function for reporting one critical path
|
||||||
auto print_path_report = [ctx](const CriticalPath &path) {
|
auto print_path_report = [ctx](const CriticalPath &path) {
|
||||||
delay_t total(0), logic_total(0), route_total(0);
|
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) {
|
if (!ctx->disable_critical_path_source_print) {
|
||||||
print_net_source(net);
|
print_net_source(ctx, net);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user