aboutsummaryrefslogtreecommitdiffstats
path: root/common/timing.cc
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-03-01 15:18:58 +0000
committergatecat <gatecat@ds0.me>2021-03-04 10:29:36 +0000
commit0528ceead1276171fff4ecaa3aafe6b0e9c8ffa5 (patch)
tree36b9f3c052b38a0c3249f4fc79a652d415a05308 /common/timing.cc
parent9c8d1bd6e3e366194dba66e994cf073fdfd902e8 (diff)
downloadnextpnr-0528ceead1276171fff4ecaa3aafe6b0e9c8ffa5.tar.gz
nextpnr-0528ceead1276171fff4ecaa3aafe6b0e9c8ffa5.tar.bz2
nextpnr-0528ceead1276171fff4ecaa3aafe6b0e9c8ffa5.zip
timing: Add forward path walking
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'common/timing.cc')
-rw-r--r--common/timing.cc90
1 files changed, 90 insertions, 0 deletions
diff --git a/common/timing.cc b/common/timing.cc
index b34fae1e..d492f574 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -36,6 +36,8 @@ void TimingAnalyser::setup()
get_cell_delays();
topo_sort();
setup_port_domains();
+ reset_times();
+ walk_forward();
}
void TimingAnalyser::init_ports()
@@ -232,6 +234,94 @@ void TimingAnalyser::setup_port_domains()
}
}
+void TimingAnalyser::reset_times()
+{
+ for (auto &port : ports) {
+ auto do_reset = [&](std::unordered_map<domain_id_t, ArrivReqTime> &times) {
+ for (auto &t : times) {
+ t.second.value = init_delay;
+ t.second.path_length = 0;
+ t.second.bwd_min = CellPortKey();
+ t.second.bwd_max = CellPortKey();
+ }
+ };
+ do_reset(port.second.arrival);
+ do_reset(port.second.required);
+ for (auto &dp : port.second.domain_pairs) {
+ dp.second.setup_slack = std::numeric_limits<delay_t>::max();
+ dp.second.hold_slack = std::numeric_limits<delay_t>::max();
+ dp.second.max_path_length = 0;
+ dp.second.criticality = 0;
+ dp.second.budget = 0;
+ }
+ }
+}
+
+void TimingAnalyser::set_arrival_time(CellPortKey target, domain_id_t domain, DelayPair arrival, int path_length,
+ CellPortKey prev)
+{
+ auto &arr = ports.at(target).arrival.at(domain);
+ if (arrival.max_delay > arr.value.max_delay) {
+ arr.value.max_delay = arrival.max_delay;
+ arr.bwd_max = prev;
+ }
+ if (!setup_only && (arrival.min_delay < arr.value.min_delay)) {
+ arr.value.min_delay = arrival.min_delay;
+ arr.bwd_min = prev;
+ }
+ arr.path_length = std::max(arr.path_length, path_length);
+}
+
+void TimingAnalyser::walk_forward()
+{
+ // Assign initial arrival time to domain startpoints
+ for (domain_id_t dom_id = 0; dom_id < domain_id_t(domains.size()); ++dom_id) {
+ auto &dom = domains.at(dom_id);
+ for (auto &sp : dom.startpoints) {
+ auto &pd = ports.at(sp.first);
+ DelayPair init_arrival(0);
+ CellPortKey clock_key;
+ // TODO: clock routing delay, if analysis of that is enabled
+ if (sp.second != IdString()) {
+ // clocked startpoints have a clock-to-out time
+ for (auto &fanin : pd.cell_arcs) {
+ if (fanin.type == CellArc::CLK_TO_Q && fanin.other_port == sp.second) {
+ init_arrival = init_arrival + fanin.value.delayPair();
+ break;
+ }
+ }
+ clock_key = CellPortKey(sp.first.cell, sp.second);
+ }
+ set_arrival_time(sp.first, dom_id, init_arrival, 1, clock_key);
+ }
+ }
+ // Walk forward in topological order
+ for (auto p : topological_order) {
+ auto &pd = ports.at(p);
+ for (auto &arr : pd.arrival) {
+ if (pd.type == PORT_OUT) {
+ // Output port: propagate delay through net, adding route delay
+ NetInfo *net = port_info(p).net;
+ if (net != nullptr)
+ for (auto &usr : net->users) {
+ CellPortKey usr_key(usr);
+ auto &usr_pd = ports.at(usr_key);
+ set_arrival_time(usr_key, arr.first, arr.second.value + usr_pd.route_delay,
+ arr.second.path_length, p);
+ }
+ } else if (pd.type == PORT_IN) {
+ // Input port; propagate delay through cell, adding combinational delay
+ for (auto &fanout : pd.cell_arcs) {
+ if (fanout.type != CellArc::COMBINATIONAL)
+ continue;
+ set_arrival_time(CellPortKey(p.cell, fanout.other_port), arr.first,
+ arr.second.value + fanout.value.delayPair(), arr.second.path_length + 1, p);
+ }
+ }
+ }
+ }
+}
+
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);