aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-03-03 13:01:54 +0000
committergatecat <gatecat@ds0.me>2021-03-04 10:29:36 +0000
commitbbf5a7d46120cef4f3e3a2214df8f9b524410a4b (patch)
tree57696a81ebf3ef1b8a74bfa5a634dd7f0e95028f /common
parente681e0f14cc4ed65891f35b042a59eaee483669f (diff)
downloadnextpnr-bbf5a7d46120cef4f3e3a2214df8f9b524410a4b.tar.gz
nextpnr-bbf5a7d46120cef4f3e3a2214df8f9b524410a4b.tar.bz2
nextpnr-bbf5a7d46120cef4f3e3a2214df8f9b524410a4b.zip
timing: Add support for critical path printing
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'common')
-rw-r--r--common/timing.cc62
-rw-r--r--common/timing.h7
2 files changed, 69 insertions, 0 deletions
diff --git a/common/timing.cc b/common/timing.cc
index 2a143854..5eae6db3 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -43,6 +43,7 @@ void TimingAnalyser::setup()
compute_slack();
compute_criticality();
print_fmax();
+ print_report();
}
void TimingAnalyser::init_ports()
@@ -457,6 +458,67 @@ void TimingAnalyser::compute_criticality()
}
}
+std::vector<CellPortKey> TimingAnalyser::get_failing_eps(domain_id_t domain_pair, int count)
+{
+ std::vector<CellPortKey> failing_eps;
+ delay_t last_slack = std::numeric_limits<delay_t>::min();
+ auto &dp = domain_pairs.at(domain_pair);
+ auto &cap_d = domains.at(dp.key.capture);
+ while (int(failing_eps.size()) < count) {
+ CellPortKey next;
+ delay_t next_slack = std::numeric_limits<delay_t>::max();
+ for (auto ep : cap_d.endpoints) {
+ auto &pd = ports.at(ep.first);
+ if (!pd.domain_pairs.count(domain_pair))
+ continue;
+ delay_t ep_slack = pd.domain_pairs.at(domain_pair).setup_slack;
+ if (ep_slack < next_slack && ep_slack > last_slack) {
+ next = ep.first;
+ next_slack = ep_slack;
+ }
+ }
+ if (next == CellPortKey())
+ break;
+ failing_eps.push_back(next);
+ last_slack = next_slack;
+ }
+ return failing_eps;
+}
+
+void TimingAnalyser::print_critical_path(CellPortKey endpoint, domain_id_t domain_pair)
+{
+ CellPortKey cursor = endpoint;
+ auto &dp = domain_pairs.at(domain_pair);
+ log(" endpoint %s.%s (slack %.02fns):\n", ctx->nameOf(cursor.cell), ctx->nameOf(cursor.port),
+ ctx->getDelayNS(ports.at(cursor).domain_pairs.at(domain_pair).setup_slack));
+ while (cursor != CellPortKey()) {
+ log(" %s.%s (net %s)\n", ctx->nameOf(cursor.cell), ctx->nameOf(cursor.port),
+ ctx->nameOf(get_net_or_empty(ctx->cells.at(cursor.cell).get(), cursor.port)));
+ if (!ports.at(cursor).arrival.count(dp.key.launch))
+ break;
+ cursor = ports.at(cursor).arrival.at(dp.key.launch).bwd_max;
+ }
+}
+
+namespace {
+const char *edge_name(ClockEdge edge) { return (edge == FALLING_EDGE) ? "negedge" : "posedge"; }
+} // namespace
+
+void TimingAnalyser::print_report()
+{
+ for (int i = 0; i < int(domain_pairs.size()); i++) {
+ auto &dp = domain_pairs.at(i);
+ auto &launch = domains.at(dp.key.launch);
+ auto &capture = domains.at(dp.key.capture);
+ log("Worst endpoints for %s %s -> %s %s\n", edge_name(launch.key.edge), ctx->nameOf(launch.key.clock),
+ edge_name(capture.key.edge), ctx->nameOf(capture.key.clock));
+ auto failing_eps = get_failing_eps(i, 5);
+ for (auto &ep : failing_eps)
+ print_critical_path(ep, i);
+ log_break();
+ }
+}
+
domain_id_t TimingAnalyser::domain_id(IdString cell, IdString clock_port, ClockEdge edge)
{
return domain_id(ctx->cells.at(cell)->ports.at(clock_port).net, edge);
diff --git a/common/timing.h b/common/timing.h
index 18f21f15..6928b11f 100644
--- a/common/timing.h
+++ b/common/timing.h
@@ -45,6 +45,7 @@ struct CellPortKey
}
};
inline bool operator==(const CellPortKey &other) const { return (cell == other.cell) && (port == other.port); }
+ inline bool operator!=(const CellPortKey &other) const { return (cell != other.cell) || (port != other.port); }
inline bool operator<(const CellPortKey &other) const
{
return cell == other.cell ? port < other.port : cell < other.cell;
@@ -145,6 +146,12 @@ struct TimingAnalyser
void compute_criticality();
void print_fmax();
+ void print_report();
+
+ // get the N most failing endpoints for a given domain pair
+ std::vector<CellPortKey> get_failing_eps(domain_id_t domain_pair, int count);
+ // print the critical path for an endpoint and domain pair
+ void print_critical_path(CellPortKey endpoint, domain_id_t domain_pair);
const DelayPair init_delay{std::numeric_limits<delay_t>::max(), std::numeric_limits<delay_t>::lowest()};