diff options
author | gatecat <gatecat@ds0.me> | 2021-02-26 10:38:39 +0000 |
---|---|---|
committer | gatecat <gatecat@ds0.me> | 2021-03-04 10:29:36 +0000 |
commit | fac6a6c068a7672e59796b542afe9a904b6dc04b (patch) | |
tree | 696980a69562afe35b6c8b777458e440d00d1fcd | |
parent | 1aab019f1e8ba53ba4810b0303536d952dc63b31 (diff) | |
download | nextpnr-fac6a6c068a7672e59796b542afe9a904b6dc04b.tar.gz nextpnr-fac6a6c068a7672e59796b542afe9a904b6dc04b.tar.bz2 nextpnr-fac6a6c068a7672e59796b542afe9a904b6dc04b.zip |
timing: Data structures for STA rewrite
Signed-off-by: gatecat <gatecat@ds0.me>
-rw-r--r-- | common/timing.h | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/common/timing.h b/common/timing.h index f1d18e8a..9b9b99e1 100644 --- a/common/timing.h +++ b/common/timing.h @@ -24,6 +24,128 @@ NEXTPNR_NAMESPACE_BEGIN +struct CellPortKey +{ + IdString cell, port; + struct Hash + { + inline std::size_t operator()(const CellPortKey &arg) const noexcept + { + std::size_t seed = std::hash<IdString>()(arg.cell); + seed ^= std::hash<IdString>()(arg.port) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } + }; + inline bool operator==(const CellPortKey &other) const { return (cell == other.cell) && (port == other.port); } +}; + +struct NetPortKey +{ + IdString net; + size_t idx; + static const size_t DRIVER_IDX = std::numeric_limits<size_t>::max(); + + inline bool is_driver() const { return (idx == DRIVER_IDX); } + inline size_t user_idx() const + { + NPNR_ASSERT(idx != DRIVER_IDX); + return idx; + } + + struct Hash + { + std::size_t operator()(const NetPortKey &arg) const noexcept + { + std::size_t seed = std::hash<IdString>()(arg.net); + seed ^= std::hash<size_t>()(arg.idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } + }; + inline bool operator==(const NetPortKey &other) const { return (net == other.net) && (idx == other.idx); } +}; + +struct ClockDomainKey +{ + IdString clock; + ClockEdge edge; + // probably also need something here to deal with constraints + inline bool is_async() const { return clock == IdString(); } + + struct Hash + { + std::size_t operator()(const ClockDomainKey &arg) const noexcept + { + std::size_t seed = std::hash<IdString>()(arg.clock); + seed ^= std::hash<int>()(int(arg.edge)) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } + }; + inline bool operator==(const ClockDomainKey &other) const { return (clock == other.clock) && (edge == other.edge); } +}; + +struct TimingAnalyser +{ + public: + TimingAnalyser(Context *ctx) : ctx(ctx){}; + + private: + // 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 + { + DelayPair value; + CellPortKey bwd_min, bwd_max; + int path_length; + }; + // Data per port-domain tuple + struct PortDomainData + { + ArrivReqTime arrival, required; + delay_t setup_slack = std::numeric_limits<delay_t>::max(), hold_slack = std::numeric_limits<delay_t>::max(); + delay_t budget = std::numeric_limits<delay_t>::max(); + int max_path_length = 0; + float criticality = 0; + }; + + // A cell timing arc, used to cache cell timings and reduce the number of potentially-expensive Arch API calls + struct CellArc + { + enum ArcType + { + COMBINATIONAL, + SETUP, + HOLD, + CLK_TO_Q + } type; + IdString other_port; + DelayQuad value; + // Clock polarity, not used for combinational arcs + ClockEdge edge; + }; + + // Timing data for every cell port + struct PerPort + { + CellPortKey cell_port; + NetPortKey net_port; + // per domain timings + std::unordered_map<domain_id_t, PortDomainData> domains; + // cell timing arcs to (outputs)/from (inputs) from this port + std::vector<CellArc> cell_arcs; + // routing delay into this port (input ports only) + DelayPair route_delay; + }; + + std::unordered_map<CellPortKey, PerPort, CellPortKey::Hash> ports; + std::unordered_map<ClockDomainKey, domain_id_t, ClockDomainKey::Hash> domain_to_id; + std::vector<ClockDomainKey> id_to_domain; + + Context *ctx; +}; + // Evenly redistribute the total path slack amongst all sinks on each path void assign_budget(Context *ctx, bool quiet = false); |