Working on adding multiple domains to timing analysis
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
b6312abc5d
commit
3ca02cc55c
@ -29,6 +29,46 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
namespace {
|
||||
struct ClockEvent {
|
||||
IdString clock;
|
||||
enum {
|
||||
POSEDGE,
|
||||
NEGEDGE
|
||||
} edge;
|
||||
};
|
||||
|
||||
struct ClockPair {
|
||||
ClockEvent start, end;
|
||||
};
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
namespace std {
|
||||
|
||||
template<>
|
||||
struct hash<NEXTPNR_NAMESPACE_PREFIX ClockEvent> {
|
||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX ClockEvent &obj) const noexcept {
|
||||
std::size_t seed = 0;
|
||||
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(obj.clock));
|
||||
boost::hash_combine(seed, hash<int>()(int(obj.edge)));
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<NEXTPNR_NAMESPACE_PREFIX ClockPair> {
|
||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX ClockPair &obj) const noexcept {
|
||||
std::size_t seed = 0;
|
||||
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX ClockEvent>()(obj.start));
|
||||
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX ClockEvent>()(obj.start));
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
typedef std::vector<const PortRef *> PortRefVector;
|
||||
typedef std::map<int, unsigned> DelayFrequency;
|
||||
|
||||
@ -41,11 +81,20 @@ struct Timing
|
||||
PortRefVector *crit_path;
|
||||
DelayFrequency *slack_histogram;
|
||||
|
||||
struct ClockDomain
|
||||
{
|
||||
IdString net;
|
||||
enum {
|
||||
RISING,
|
||||
FALLING
|
||||
} edge;
|
||||
};
|
||||
|
||||
struct TimingData
|
||||
{
|
||||
TimingData() : max_arrival(), max_path_length(), min_remaining_budget() {}
|
||||
TimingData(delay_t max_arrival) : max_arrival(max_arrival), max_path_length(), min_remaining_budget() {}
|
||||
delay_t max_arrival;
|
||||
TimingData(ClockPair dest, delay_t max_arrival) : max_path_length(), min_remaining_budget() {}
|
||||
std::unordedelay_t max_arrival;
|
||||
unsigned max_path_length = 0;
|
||||
delay_t min_remaining_budget;
|
||||
bool false_startpoint = false;
|
||||
@ -65,7 +114,7 @@ struct Timing
|
||||
// First, compute the topographical order of nets to walk through the circuit, assuming it is a _acyclic_ graph
|
||||
// TODO(eddieh): Handle the case where it is cyclic, e.g. combinatorial loops
|
||||
std::vector<NetInfo *> topographical_order;
|
||||
std::unordered_map<const NetInfo *, TimingData> net_data;
|
||||
std::unordered_map<const NetInfo *, std::unordered_map<ClockEvent, TimingData>> net_data;
|
||||
// In lieu of deleting edges from the graph, simply count the number of fanins to each output port
|
||||
std::unordered_map<const PortInfo *, unsigned> port_fanin;
|
||||
|
||||
@ -92,13 +141,13 @@ struct Timing
|
||||
DelayInfo clkToQ;
|
||||
ctx->getCellDelay(cell.second.get(), clockPort, o->name, clkToQ);
|
||||
topographical_order.emplace_back(o->net);
|
||||
net_data.emplace(o->net, TimingData{clkToQ.maxDelay()});
|
||||
net_data[o->net][ClockEvent{IdString(), ClockEvent::POSEDGE}] = TimingData{clkToQ.maxDelay()};
|
||||
} else {
|
||||
if (portClass == TMG_STARTPOINT || portClass == TMG_GEN_CLOCK || portClass == TMG_IGNORE) {
|
||||
topographical_order.emplace_back(o->net);
|
||||
TimingData td;
|
||||
td.false_startpoint = (portClass == TMG_GEN_CLOCK || portClass == TMG_IGNORE);
|
||||
net_data.emplace(o->net, std::move(td));
|
||||
net_data[o->net][ClockEvent{IdString(), ClockEvent::POSEDGE}] = td;
|
||||
}
|
||||
// Otherwise, for all driven input ports on this cell, if a timing arc exists between the input and
|
||||
// the current output port, increment fanin counter
|
||||
@ -174,7 +223,10 @@ struct Timing
|
||||
|
||||
// Go forwards topographically to find the maximum arrival time and max path length for each net
|
||||
for (auto net : topographical_order) {
|
||||
auto &nd = net_data.at(net);
|
||||
auto &nd_map = net_data.at(net);
|
||||
for (auto &startdomain : nd_map) {
|
||||
ClockEvent start_clk = startdomain.first;
|
||||
auto &nd = startdomain.second;
|
||||
const auto net_arrival = nd.max_arrival;
|
||||
const auto net_length_plus_one = nd.max_path_length + 1;
|
||||
nd.min_remaining_budget = clk_period;
|
||||
@ -195,7 +247,7 @@ struct Timing
|
||||
bool is_path = ctx->getCellDelay(usr.cell, usr.port, port.first, comb_delay);
|
||||
if (!is_path)
|
||||
continue;
|
||||
auto &data = net_data[port.second.net];
|
||||
auto &data = net_data[port.second.net][start_clk];
|
||||
auto &arrival = data.max_arrival;
|
||||
arrival = std::max(arrival, usr_arrival + comb_delay.maxDelay());
|
||||
if (!budget_override) { // Do not increment path length if budget overriden since it doesn't
|
||||
@ -208,6 +260,8 @@ struct Timing
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const NetInfo *crit_net = nullptr;
|
||||
|
||||
// Now go backwards topographically to determine the minimum path slack, and to distribute all path slack evenly
|
||||
|
Loading…
Reference in New Issue
Block a user