From a8c110b045744626f882e2a31ed8b3364f9a65db Mon Sep 17 00:00:00 2001 From: Ross Schlaikjer Date: Sun, 30 Aug 2020 17:43:29 -0400 Subject: [PATCH 1/3] Add option to print critical path source code In order to make debugging the critical path easier, add an option that will log the location each net was defined, if known. If the file that contains the definition is known, and is readable, also print the part of the source HDL responsible for the signal definition. --- common/command.cc | 11 +++++++ common/nextpnr.h | 5 +++ common/timing.cc | 78 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/common/command.cc b/common/command.cc index 3dc0d968..d0087fc9 100644 --- a/common/command.cc +++ b/common/command.cc @@ -158,6 +158,10 @@ po::options_description CommandHandler::getGeneralOptions() general.add_options()("no-tmdriv", "disable timing-driven placement"); general.add_options()("sdf", po::value(), "SDF delay back-annotation file to write"); general.add_options()("sdf-cvc", "enable tweaks for SDF file compatibility with the CVC simulator"); + general.add_options()("print-critical-path-source", + "print the source code associated with each net in the critical path"); + general.add_options()("critical-path-source-max-lines", po::value(), + "max number of source lines to print per critical path report entry"); general.add_options()("placed-svg", po::value(), "write render of placement to SVG file"); general.add_options()("routed-svg", po::value(), "write render of routing to SVG file"); @@ -179,6 +183,13 @@ void CommandHandler::setupContext(Context *ctx) ctx->debug = true; } + if (vm.count("print-critical-path-source")) { + ctx->print_critical_path_source = true; + } + if (vm.count("critical-path-source-max-lines")) { + ctx->critical_path_source_max_lines = vm["critical-path-source-max-lines"].as(); + } + if (vm.count("force")) { ctx->force = true; } diff --git a/common/nextpnr.h b/common/nextpnr.h index 4d481d06..fc5e7c46 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -861,6 +861,11 @@ struct Context : Arch, DeterministicRNG bool debug = false; bool force = false; + // Print verilog sources for nets in critical path? + bool print_critical_path_source = false; + // Max line count to print for critical path sources + int critical_path_source_max_lines = 8; + Context(ArchArgs args) : Arch(args) {} // -------------------------------------------------------------- diff --git a/common/timing.cc b/common/timing.cc index d4d33183..b67f2ef8 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -811,6 +812,80 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p } if (print_path) { + static auto print_net_source = [](Context *ctx, NetInfo *net) { + 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, deepest source last + 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)); + + // For each source entry, split iinto filename, start line/character + // and end line/character + const unsigned entry_count = source_entries.size(); + log_info(" Defined in:\n"); + for (unsigned i = 0; i < entry_count; i++) { + const std::string source_entry = source_entries[i]; + const bool is_final_entry = i == entry_count - 1; + + log_info(" %s\n", source_entry.c_str()); + + // Split the source entry to get the filename + const size_t filename_split = source_entry.find(":"); + const std::string filename = source_entry.substr(0, filename_split); + const std::string location_tuple = source_entry.substr(filename_split + 1); + + // Split the location tuple into start/end groups + const size_t start_end_split = location_tuple.find("-"); + const std::string code_start = location_tuple.substr(0, start_end_split); + const std::string code_end = location_tuple.substr(start_end_split + 1); + + // Extract just the line number from those tuples + const int code_start_line = std::atoi(code_start.substr(0, code_start.find(".")).c_str()); + const int code_end_line = std::atoi(code_end.substr(0, code_end.find(".")).c_str()); + + // Try and stat the source file + std::ifstream in(filename); + if (!in) { + // Failed to find source file, can't print the actual source + return; + } + + // Skip through to the start line + in.seekg(std::ios::beg); + for (int i = 0; i < code_start_line - 1; ++i) { + in.ignore(std::numeric_limits::max(), '\n'); + } + // Log each line til we hit the end line / max line count + // For non-final entries, just print one line so we don't spam too heavily + int max_print_lines = ctx->critical_path_source_max_lines - 1; + if (!is_final_entry) { + max_print_lines = 0; // Compare is inclusive + } + const int print_end = + ((code_end_line < code_start_line + max_print_lines) ? code_end_line + : code_start_line + max_print_lines); + for (int i = code_start_line; i <= print_end; i++) { + std::string line; + getline(in, line); + // Strip any whitespace from the start of the line, since we are already aligning it + line.erase(line.begin(), + std::find_if(line.begin(), line.end(), [](char c) { return !(c == ' ' || c == '\t'); })); + log_info(" %s\n", line.c_str()); + } + } + }; + auto print_path_report = [ctx](ClockPair &clocks, PortRefVector &crit_path) { delay_t total = 0, logic_total = 0, route_total = 0; auto &front = crit_path.front(); @@ -888,6 +963,9 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p cursor = ctx->getPipSrcWire(pip); } } + if (ctx->print_critical_path_source) { + print_net_source(ctx, net); + } last_port = sink->port; } int clockCount = 0; From cba4753c22f07173b1992a2dee08cc5a4a3c971e Mon Sep 17 00:00:00 2001 From: Ross Schlaikjer Date: Sun, 30 Aug 2020 18:19:41 -0400 Subject: [PATCH 2/3] Only print filenames for now, default on --- common/command.cc | 13 ++++------ common/nextpnr.h | 6 ++--- common/timing.cc | 61 ++++++----------------------------------------- 3 files changed, 13 insertions(+), 67 deletions(-) diff --git a/common/command.cc b/common/command.cc index d0087fc9..f0d028ce 100644 --- a/common/command.cc +++ b/common/command.cc @@ -158,10 +158,8 @@ po::options_description CommandHandler::getGeneralOptions() general.add_options()("no-tmdriv", "disable timing-driven placement"); general.add_options()("sdf", po::value(), "SDF delay back-annotation file to write"); general.add_options()("sdf-cvc", "enable tweaks for SDF file compatibility with the CVC simulator"); - general.add_options()("print-critical-path-source", - "print the source code associated with each net in the critical path"); - general.add_options()("critical-path-source-max-lines", po::value(), - "max number of source lines to print per critical path report entry"); + general.add_options()("no-print-critical-path-source", + "disable printing of the source lines associated with each net in the critical path"); general.add_options()("placed-svg", po::value(), "write render of placement to SVG file"); general.add_options()("routed-svg", po::value(), "write render of routing to SVG file"); @@ -183,11 +181,8 @@ void CommandHandler::setupContext(Context *ctx) ctx->debug = true; } - if (vm.count("print-critical-path-source")) { - ctx->print_critical_path_source = true; - } - if (vm.count("critical-path-source-max-lines")) { - ctx->critical_path_source_max_lines = vm["critical-path-source-max-lines"].as(); + if (vm.count("no-print-critical-path-source")) { + ctx->disable_critical_path_source_print = true; } if (vm.count("force")) { diff --git a/common/nextpnr.h b/common/nextpnr.h index fc5e7c46..f9376fea 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -861,10 +861,8 @@ struct Context : Arch, DeterministicRNG bool debug = false; bool force = false; - // Print verilog sources for nets in critical path? - bool print_critical_path_source = false; - // Max line count to print for critical path sources - int critical_path_source_max_lines = 8; + // Should we disable printing of the location of nets in the critical path? + bool disable_critical_path_source_print = false; Context(ArchArgs args) : Arch(args) {} diff --git a/common/timing.cc b/common/timing.cc index b67f2ef8..2f62bd2f 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -813,13 +813,15 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p if (print_path) { static auto print_net_source = [](Context *ctx, 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, deepest source last + // 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; @@ -830,59 +832,10 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p // Ensure we emplace the final entry source_entries.emplace_back(sourcelist.substr(prev, current - prev)); - // For each source entry, split iinto filename, start line/character - // and end line/character - const unsigned entry_count = source_entries.size(); + // Iterate and print our source list at the correct indentation level log_info(" Defined in:\n"); - for (unsigned i = 0; i < entry_count; i++) { - const std::string source_entry = source_entries[i]; - const bool is_final_entry = i == entry_count - 1; - - log_info(" %s\n", source_entry.c_str()); - - // Split the source entry to get the filename - const size_t filename_split = source_entry.find(":"); - const std::string filename = source_entry.substr(0, filename_split); - const std::string location_tuple = source_entry.substr(filename_split + 1); - - // Split the location tuple into start/end groups - const size_t start_end_split = location_tuple.find("-"); - const std::string code_start = location_tuple.substr(0, start_end_split); - const std::string code_end = location_tuple.substr(start_end_split + 1); - - // Extract just the line number from those tuples - const int code_start_line = std::atoi(code_start.substr(0, code_start.find(".")).c_str()); - const int code_end_line = std::atoi(code_end.substr(0, code_end.find(".")).c_str()); - - // Try and stat the source file - std::ifstream in(filename); - if (!in) { - // Failed to find source file, can't print the actual source - return; - } - - // Skip through to the start line - in.seekg(std::ios::beg); - for (int i = 0; i < code_start_line - 1; ++i) { - in.ignore(std::numeric_limits::max(), '\n'); - } - // Log each line til we hit the end line / max line count - // For non-final entries, just print one line so we don't spam too heavily - int max_print_lines = ctx->critical_path_source_max_lines - 1; - if (!is_final_entry) { - max_print_lines = 0; // Compare is inclusive - } - const int print_end = - ((code_end_line < code_start_line + max_print_lines) ? code_end_line - : code_start_line + max_print_lines); - for (int i = code_start_line; i <= print_end; i++) { - std::string line; - getline(in, line); - // Strip any whitespace from the start of the line, since we are already aligning it - line.erase(line.begin(), - std::find_if(line.begin(), line.end(), [](char c) { return !(c == ' ' || c == '\t'); })); - log_info(" %s\n", line.c_str()); - } + for (auto entry : source_entries) { + log_info(" %s\n", entry.c_str()); } }; @@ -963,7 +916,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p cursor = ctx->getPipSrcWire(pip); } } - if (ctx->print_critical_path_source) { + if (!ctx->disable_critical_path_source_print) { print_net_source(ctx, net); } last_port = sink->port; From c30cadd19caf16edebdc676e17d9f6280ef59361 Mon Sep 17 00:00:00 2001 From: Ross Schlaikjer Date: Sun, 30 Aug 2020 18:22:05 -0400 Subject: [PATCH 3/3] No longer need fstream include --- common/timing.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/common/timing.cc b/common/timing.cc index 2f62bd2f..8b35e41c 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include