From bbf5a7d46120cef4f3e3a2214df8f9b524410a4b Mon Sep 17 00:00:00 2001 From: gatecat Date: Wed, 3 Mar 2021 13:01:54 +0000 Subject: timing: Add support for critical path printing Signed-off-by: gatecat --- common/timing.cc | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ common/timing.h | 7 +++++++ 2 files changed, 69 insertions(+) (limited to 'common') 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 TimingAnalyser::get_failing_eps(domain_id_t domain_pair, int count) +{ + std::vector failing_eps; + delay_t last_slack = std::numeric_limits::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::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 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::max(), std::numeric_limits::lowest()}; -- cgit v1.2.3