From 9c8d1bd6e3e366194dba66e994cf073fdfd902e8 Mon Sep 17 00:00:00 2001 From: gatecat Date: Mon, 1 Mar 2021 14:50:00 +0000 Subject: timing: Compute domain pairs Signed-off-by: gatecat --- common/timing.cc | 33 +++++++++++++++++++++++++-------- common/timing.h | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 13 deletions(-) (limited to 'common') diff --git a/common/timing.cc b/common/timing.cc index 4daa19b0..b34fae1e 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -180,7 +180,7 @@ void TimingAnalyser::setup_port_domains() // registered outputs are startpoints auto dom = domain_id(port.cell, fanin.other_port, fanin.edge); // create per-domain data - pd.domains[dom].has_arrival = true; + pd.arrival[dom]; domains.at(dom).startpoints.emplace_back(port, fanin.other_port); } // copy domains across routing @@ -214,7 +214,7 @@ void TimingAnalyser::setup_port_domains() // registered inputs are startpoints auto dom = domain_id(port.cell, fanout.other_port, fanout.edge); // create per-domain data - pd.domains[dom].has_required = true; + pd.required[dom]; domains.at(dom).startpoints.emplace_back(port, fanout.other_port); } // copy port to driver @@ -222,28 +222,45 @@ void TimingAnalyser::setup_port_domains() copy_domains(port, CellPortKey(pi.net->driver), true); } } + // Iterate over ports and find domain paris + for (auto port : topological_order) { + auto &pd = ports.at(port); + for (auto &arr : pd.arrival) + for (auto &req : pd.required) { + pd.domain_pairs[domain_pair_id(arr.first, req.first)]; + } + } } -TimingAnalyser::domain_id_t TimingAnalyser::domain_id(IdString cell, IdString clock_port, ClockEdge edge) +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); } -TimingAnalyser::domain_id_t TimingAnalyser::domain_id(const NetInfo *net, ClockEdge edge) +domain_id_t TimingAnalyser::domain_id(const NetInfo *net, ClockEdge edge) { NPNR_ASSERT(net != nullptr); ClockDomainKey key{net->name, edge}; - auto inserted = domain_to_id.emplace(key, domain_to_id.size()); + auto inserted = domain_to_id.emplace(key, domains.size()); if (inserted.second) { domains.emplace_back(key); } return inserted.first->second; } +domain_id_t TimingAnalyser::domain_pair_id(domain_id_t launch, domain_id_t capture) +{ + ClockDomainPairKey key{launch, capture}; + auto inserted = pair_to_id.emplace(key, domain_pairs.size()); + if (inserted.second) { + domain_pairs.emplace_back(key); + } + return inserted.first->second; +} + void TimingAnalyser::copy_domains(const CellPortKey &from, const CellPortKey &to, bool backward) { auto &f = ports.at(from), &t = ports.at(to); - for (auto &dom : f.domains) - if (backward ? dom.second.has_required : dom.second.has_arrival) - (backward ? t.domains[dom.first].has_required : t.domains[dom.first].has_arrival) = true; + for (auto &dom : (backward ? f.required : f.arrival)) + (backward ? t.required : t.arrival)[dom.first]; } CellInfo *TimingAnalyser::cell_info(const CellPortKey &key) { return ctx->cells.at(key.cell).get(); } diff --git a/common/timing.h b/common/timing.h index 9aa15e59..9540b6f6 100644 --- a/common/timing.h +++ b/common/timing.h @@ -100,6 +100,27 @@ struct ClockDomainKey inline bool operator==(const ClockDomainKey &other) const { return (clock == other.clock) && (edge == other.edge); } }; +typedef int domain_id_t; + +struct ClockDomainPairKey +{ + domain_id_t launch, capture; + ClockDomainPairKey(domain_id_t launch, domain_id_t capture) : launch(launch), capture(capture){}; + inline bool operator==(const ClockDomainPairKey &other) const + { + return (launch == other.launch) && (capture == other.capture); + } + struct Hash + { + std::size_t operator()(const ClockDomainPairKey &arg) const noexcept + { + std::size_t seed = std::hash()(arg.launch); + seed ^= std::hash()(arg.capture) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } + }; +}; + struct TimingAnalyser { public: @@ -113,7 +134,6 @@ struct TimingAnalyser void setup_port_domains(); // To avoid storing the domain tag structure (which could get large when considering more complex constrained tag // cases), assign each domain an ID and use that instead - typedef int domain_id_t; // An arrival or required time entry. Stores both the min/max delays; and the traversal to reach them for critical // path reporting struct ArrivReqTime @@ -123,10 +143,8 @@ struct TimingAnalyser int path_length; }; // Data per port-domain tuple - struct PortDomainData + struct PortDomainPairData { - bool has_arrival = false, has_required = false; - ArrivReqTime arrival, required; delay_t setup_slack = std::numeric_limits::max(), hold_slack = std::numeric_limits::max(); delay_t budget = std::numeric_limits::max(); int max_path_length = 0; @@ -163,7 +181,9 @@ struct TimingAnalyser NetPortKey net_port; PortType type; // per domain timings - std::unordered_map domains; + std::unordered_map arrival; + std::unordered_map required; + std::unordered_map domain_pairs; // cell timing arcs to (outputs)/from (inputs) from this port std::vector cell_arcs; // routing delay into this port (input ports only) @@ -178,17 +198,26 @@ struct TimingAnalyser std::vector> startpoints, endpoints; }; + struct PerDomainPair + { + PerDomainPair(ClockDomainPairKey key) : key(key){}; + ClockDomainPairKey key; + }; + CellInfo *cell_info(const CellPortKey &key); PortInfo &port_info(const CellPortKey &key); domain_id_t domain_id(IdString cell, IdString clock_port, ClockEdge edge); domain_id_t domain_id(const NetInfo *net, ClockEdge edge); + domain_id_t domain_pair_id(domain_id_t launch, domain_id_t capture); void copy_domains(const CellPortKey &from, const CellPortKey &to, bool backwards); std::unordered_map ports; std::unordered_map domain_to_id; + std::unordered_map pair_to_id; std::vector domains; + std::vector domain_pairs; std::vector topological_order; -- cgit v1.2.3