aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-02-26 10:38:39 +0000
committergatecat <gatecat@ds0.me>2021-03-04 10:29:36 +0000
commitfac6a6c068a7672e59796b542afe9a904b6dc04b (patch)
tree696980a69562afe35b6c8b777458e440d00d1fcd /common
parent1aab019f1e8ba53ba4810b0303536d952dc63b31 (diff)
downloadnextpnr-fac6a6c068a7672e59796b542afe9a904b6dc04b.tar.gz
nextpnr-fac6a6c068a7672e59796b542afe9a904b6dc04b.tar.bz2
nextpnr-fac6a6c068a7672e59796b542afe9a904b6dc04b.zip
timing: Data structures for STA rewrite
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'common')
-rw-r--r--common/timing.h122
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);