diff --git a/common/kernel/timing.cc b/common/kernel/timing.cc index 17422cc0..6d53594a 100644 --- a/common/kernel/timing.cc +++ b/common/kernel/timing.cc @@ -75,6 +75,7 @@ void TimingAnalyser::run(bool update_route_delays, bool update_net_timings, bool } if (update_crit_paths) { + get_min_delay_violations(); build_crit_path_reports(); } } @@ -119,7 +120,9 @@ void TimingAnalyser::get_cell_delays() continue; pd.cell_arcs.emplace_back(CellArc::SETUP, info.clock_port, DelayQuad(info.setup, info.setup), info.edge); - pd.cell_arcs.emplace_back(CellArc::HOLD, info.clock_port, DelayQuad(info.hold, info.hold), + auto hold_factor = 1; + auto hold_faked = DelayPair(hold_factor * info.hold.min_delay, hold_factor * info.hold.max_delay); + pd.cell_arcs.emplace_back(CellArc::HOLD, info.clock_port, DelayQuad(hold_faked, hold_faked), info.edge); } } @@ -572,6 +575,8 @@ void TimingAnalyser::walk_forward() 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(); + // printf("walk_forward %s.%s: init_arrival to %d - %d\n", sp.first.cell.c_str(ctx), + // sp.first.port.c_str(ctx), init_arrival.min_delay, init_arrival.max_delay); break; } } @@ -591,16 +596,26 @@ void TimingAnalyser::walk_forward() 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); + auto next_arr = arr.second.value + usr_pd.route_delay; + printf("walk_forward: propagate routing from %s.%s to %s.%s, %d - %d\n", p.cell.c_str(ctx), + p.port.c_str(ctx), usr_key.cell.c_str(ctx), usr_key.port.c_str(ctx), next_arr.min_delay, + next_arr.max_delay); + + set_arrival_time(usr_key, arr.first, next_arr, 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); + + auto next_arr = arr.second.value + fanout.value.delayPair(); + + printf("walk_forward: propagate through cell from %s.%s to %s.%s, %d - %d\n", p.cell.c_str(ctx), + p.port.c_str(ctx), p.cell.c_str(ctx), fanout.other_port.c_str(ctx), next_arr.min_delay, + next_arr.max_delay); + set_arrival_time(CellPortKey(p.cell, fanout.other_port), arr.first, next_arr, + arr.second.path_length + 1, p); } } } @@ -715,6 +730,13 @@ void TimingAnalyser::compute_slack() pd.worst_hold_slack = std::min(pd.worst_hold_slack, pdp.second.hold_slack); dp.worst_hold_slack = std::min(dp.worst_hold_slack, pdp.second.hold_slack); } + // printf("max arr: %d, min req: %d, c2c: %d, setup slack: %d\n", arr.value.maxDelay(), + // req.value.minDelay(), + // clock_to_clock, pdp.second.setup_slack); + // if (!setup_only) { + // printf("min arr: %d, max req: %d, c2c: %d, hold slack: %d\n", arr.value.minDelay(), + // req.value.maxDelay(), clock_to_clock, pdp.second.hold_slack); + // } } } } @@ -1083,6 +1105,89 @@ void TimingAnalyser::build_slack_histogram_report() } } +std::string arc_typ_to_str(TimingAnalyser::CellArc::ArcType typ) +{ + switch (typ) { + case TimingAnalyser::CellArc::COMBINATIONAL: + return "COMBINATIONAL"; + case TimingAnalyser::CellArc::SETUP: + return "SETUP"; + case TimingAnalyser::CellArc::HOLD: + return "HOLD"; + case TimingAnalyser::CellArc::CLK_TO_Q: + return "CLK_TO_Q"; + case TimingAnalyser::CellArc::STARTPOINT: + return "STARTPOINT"; + case TimingAnalyser::CellArc::ENDPOINT: + return "ENDPOINT"; + default: + return "IMPOSSIBRU"; + } +} + +std::vector TimingAnalyser::get_min_delay_violations() +{ + std::vector violations; + + for (domain_id_t capture_id = 0; capture_id < domain_id_t(domains.size()); ++capture_id) { + const auto &capture = domains.at(capture_id); + const auto &capture_clock = capture.key.clock; + + if (ctx->nets.count(capture_clock) == 0) { + continue; + } + + NetInfo *clk_net = ctx->nets.at(capture_clock).get(); + if (clk_net->clkconstr == nullptr) { + continue; + } + + DelayPair period = clk_net->clkconstr->period; + + printf("Clock %s.%s with period %f - %f\n", clk_net->driver.cell->name.c_str(ctx), + clk_net->driver.port.c_str(ctx), ctx->getDelayNS(period.minDelay()), ctx->getDelayNS(period.maxDelay())); + + for (auto &sp : capture.endpoints) { + CellInfo *ci = cell_info(sp.first); + int clkInfoCount = 0; + TimingPortClass cls = ctx->getPortTimingClass(ci, sp.first.port, clkInfoCount); + if (cls != TMG_REGISTER_INPUT) + continue; + + auto &port = ports.at(sp.first); + + auto &req = port.required.at(capture_id); + + for (auto &[launch_id, arr] : port.arrival) { + const auto &launch = domains.at(launch_id); + const auto &launch_clock = launch.key.clock; + + auto clocks = std::make_pair(launch_clock, capture_clock); + auto related_clocks = clock_delays.count(clocks) != 0; + + // Don't consider clocks without known relationships + if (launch_id != capture_id && !related_clocks) { + continue; + } + + delay_t clock_to_clock = 0; + if (related_clocks) { + clock_to_clock = clock_delays.at(clocks); + } + + auto hold_slack = arr.value.minDelay() - req.value.maxDelay() + clock_to_clock; + + printf("endpoint: %s.%s, arr: %f - %f, req: %f - %f, hold slack: %f\n", sp.first.cell.c_str(ctx), + sp.first.port.c_str(ctx), ctx->getDelayNS(arr.value.minDelay()), + ctx->getDelayNS(arr.value.maxDelay()), ctx->getDelayNS(req.value.minDelay()), + ctx->getDelayNS(req.value.maxDelay()), ctx->getDelayNS(hold_slack)); + } + } + } + + return violations; +} + 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); diff --git a/common/kernel/timing.h b/common/kernel/timing.h index 6ddd25c7..80b3079c 100644 --- a/common/kernel/timing.h +++ b/common/kernel/timing.h @@ -125,6 +125,8 @@ struct TimingAnalyser void build_crit_path_reports(); void build_slack_histogram_report(); + std::vector get_min_delay_violations(); + dict max_delay_by_domain_pairs(); // get the N worst endpoints for a given domain pair