timing: Compute domain pairs

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2021-03-01 14:50:00 +00:00
parent 534e69fbff
commit 9c8d1bd6e3
2 changed files with 59 additions and 13 deletions

View File

@ -180,7 +180,7 @@ void TimingAnalyser::setup_port_domains()
// registered outputs are startpoints // registered outputs are startpoints
auto dom = domain_id(port.cell, fanin.other_port, fanin.edge); auto dom = domain_id(port.cell, fanin.other_port, fanin.edge);
// create per-domain data // create per-domain data
pd.domains[dom].has_arrival = true; pd.arrival[dom];
domains.at(dom).startpoints.emplace_back(port, fanin.other_port); domains.at(dom).startpoints.emplace_back(port, fanin.other_port);
} }
// copy domains across routing // copy domains across routing
@ -214,7 +214,7 @@ void TimingAnalyser::setup_port_domains()
// registered inputs are startpoints // registered inputs are startpoints
auto dom = domain_id(port.cell, fanout.other_port, fanout.edge); auto dom = domain_id(port.cell, fanout.other_port, fanout.edge);
// create per-domain data // create per-domain data
pd.domains[dom].has_required = true; pd.required[dom];
domains.at(dom).startpoints.emplace_back(port, fanout.other_port); domains.at(dom).startpoints.emplace_back(port, fanout.other_port);
} }
// copy port to driver // copy port to driver
@ -222,28 +222,45 @@ void TimingAnalyser::setup_port_domains()
copy_domains(port, CellPortKey(pi.net->driver), true); 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); 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); NPNR_ASSERT(net != nullptr);
ClockDomainKey key{net->name, edge}; 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) { if (inserted.second) {
domains.emplace_back(key); domains.emplace_back(key);
} }
return inserted.first->second; 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) void TimingAnalyser::copy_domains(const CellPortKey &from, const CellPortKey &to, bool backward)
{ {
auto &f = ports.at(from), &t = ports.at(to); auto &f = ports.at(from), &t = ports.at(to);
for (auto &dom : f.domains) for (auto &dom : (backward ? f.required : f.arrival))
if (backward ? dom.second.has_required : dom.second.has_arrival) (backward ? t.required : t.arrival)[dom.first];
(backward ? t.domains[dom.first].has_required : t.domains[dom.first].has_arrival) = true;
} }
CellInfo *TimingAnalyser::cell_info(const CellPortKey &key) { return ctx->cells.at(key.cell).get(); } CellInfo *TimingAnalyser::cell_info(const CellPortKey &key) { return ctx->cells.at(key.cell).get(); }

View File

@ -100,6 +100,27 @@ struct ClockDomainKey
inline bool operator==(const ClockDomainKey &other) const { return (clock == other.clock) && (edge == other.edge); } 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<domain_id_t>()(arg.launch);
seed ^= std::hash<domain_id_t>()(arg.capture) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
};
struct TimingAnalyser struct TimingAnalyser
{ {
public: public:
@ -113,7 +134,6 @@ struct TimingAnalyser
void setup_port_domains(); void setup_port_domains();
// To avoid storing the domain tag structure (which could get large when considering more complex constrained tag // 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 // 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 // An arrival or required time entry. Stores both the min/max delays; and the traversal to reach them for critical
// path reporting // path reporting
struct ArrivReqTime struct ArrivReqTime
@ -123,10 +143,8 @@ struct TimingAnalyser
int path_length; int path_length;
}; };
// Data per port-domain tuple // 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<delay_t>::max(), hold_slack = std::numeric_limits<delay_t>::max(); 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(); delay_t budget = std::numeric_limits<delay_t>::max();
int max_path_length = 0; int max_path_length = 0;
@ -163,7 +181,9 @@ struct TimingAnalyser
NetPortKey net_port; NetPortKey net_port;
PortType type; PortType type;
// per domain timings // per domain timings
std::unordered_map<domain_id_t, PortDomainData> domains; std::unordered_map<domain_id_t, ArrivReqTime> arrival;
std::unordered_map<domain_id_t, ArrivReqTime> required;
std::unordered_map<domain_id_t, PortDomainPairData> domain_pairs;
// cell timing arcs to (outputs)/from (inputs) from this port // cell timing arcs to (outputs)/from (inputs) from this port
std::vector<CellArc> cell_arcs; std::vector<CellArc> cell_arcs;
// routing delay into this port (input ports only) // routing delay into this port (input ports only)
@ -178,17 +198,26 @@ struct TimingAnalyser
std::vector<std::pair<CellPortKey, IdString>> startpoints, endpoints; std::vector<std::pair<CellPortKey, IdString>> startpoints, endpoints;
}; };
struct PerDomainPair
{
PerDomainPair(ClockDomainPairKey key) : key(key){};
ClockDomainPairKey key;
};
CellInfo *cell_info(const CellPortKey &key); CellInfo *cell_info(const CellPortKey &key);
PortInfo &port_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(IdString cell, IdString clock_port, ClockEdge edge);
domain_id_t domain_id(const NetInfo *net, 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); void copy_domains(const CellPortKey &from, const CellPortKey &to, bool backwards);
std::unordered_map<CellPortKey, PerPort, CellPortKey::Hash> ports; std::unordered_map<CellPortKey, PerPort, CellPortKey::Hash> ports;
std::unordered_map<ClockDomainKey, domain_id_t, ClockDomainKey::Hash> domain_to_id; std::unordered_map<ClockDomainKey, domain_id_t, ClockDomainKey::Hash> domain_to_id;
std::unordered_map<ClockDomainPairKey, domain_id_t, ClockDomainPairKey::Hash> pair_to_id;
std::vector<PerDomain> domains; std::vector<PerDomain> domains;
std::vector<PerDomainPair> domain_pairs;
std::vector<CellPortKey> topological_order; std::vector<CellPortKey> topological_order;