timing: Data structures for STA rewrite
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
parent
1aab019f1e
commit
fac6a6c068
122
common/timing.h
122
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user