aboutsummaryrefslogtreecommitdiffstats
path: root/common/timing.cc
diff options
context:
space:
mode:
authorRoss Schlaikjer <ross@schlaikjer.net>2020-08-30 17:43:29 -0400
committerRoss Schlaikjer <ross@schlaikjer.net>2020-08-30 17:43:29 -0400
commita8c110b045744626f882e2a31ed8b3364f9a65db (patch)
tree5c82e78b995de12b65f8e3cea27276673abd1631 /common/timing.cc
parentf6d436d58b8206aabe287325fc80da5521ed2e75 (diff)
downloadnextpnr-a8c110b045744626f882e2a31ed8b3364f9a65db.tar.gz
nextpnr-a8c110b045744626f882e2a31ed8b3364f9a65db.tar.bz2
nextpnr-a8c110b045744626f882e2a31ed8b3364f9a65db.zip
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.
Diffstat (limited to 'common/timing.cc')
-rw-r--r--common/timing.cc78
1 files changed, 78 insertions, 0 deletions
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 <algorithm>
#include <boost/range/adaptor/reversed.hpp>
#include <deque>
+#include <fstream>
#include <map>
#include <unordered_map>
#include <utility>
@@ -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<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));
+
+ // 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<std::streamsize>::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;