timing: Start identification of min_delay violations

This commit is contained in:
Rowan Goemans 2024-09-11 17:55:08 +02:00 committed by myrtle
parent 44665a9c4d
commit c25da06d03
2 changed files with 112 additions and 5 deletions

View File

@ -75,6 +75,7 @@ void TimingAnalyser::run(bool update_route_delays, bool update_net_timings, bool
} }
if (update_crit_paths) { if (update_crit_paths) {
get_min_delay_violations();
build_crit_path_reports(); build_crit_path_reports();
} }
} }
@ -119,7 +120,9 @@ void TimingAnalyser::get_cell_delays()
continue; continue;
pd.cell_arcs.emplace_back(CellArc::SETUP, info.clock_port, DelayQuad(info.setup, info.setup), pd.cell_arcs.emplace_back(CellArc::SETUP, info.clock_port, DelayQuad(info.setup, info.setup),
info.edge); 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); info.edge);
} }
} }
@ -572,6 +575,8 @@ void TimingAnalyser::walk_forward()
for (auto &fanin : pd.cell_arcs) { for (auto &fanin : pd.cell_arcs) {
if (fanin.type == CellArc::CLK_TO_Q && fanin.other_port == sp.second) { if (fanin.type == CellArc::CLK_TO_Q && fanin.other_port == sp.second) {
init_arrival = init_arrival + fanin.value.delayPair(); 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; break;
} }
} }
@ -591,16 +596,26 @@ void TimingAnalyser::walk_forward()
for (auto &usr : net->users) { for (auto &usr : net->users) {
CellPortKey usr_key(usr); CellPortKey usr_key(usr);
auto &usr_pd = ports.at(usr_key); auto &usr_pd = ports.at(usr_key);
set_arrival_time(usr_key, arr.first, arr.second.value + usr_pd.route_delay, auto next_arr = arr.second.value + usr_pd.route_delay;
arr.second.path_length, p); 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) { } else if (pd.type == PORT_IN) {
// Input port; propagate delay through cell, adding combinational delay // Input port; propagate delay through cell, adding combinational delay
for (auto &fanout : pd.cell_arcs) { for (auto &fanout : pd.cell_arcs) {
if (fanout.type != CellArc::COMBINATIONAL) if (fanout.type != CellArc::COMBINATIONAL)
continue; 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); 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); 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<CriticalPath> TimingAnalyser::get_min_delay_violations()
{
std::vector<CriticalPath> 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) 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);

View File

@ -125,6 +125,8 @@ struct TimingAnalyser
void build_crit_path_reports(); void build_crit_path_reports();
void build_slack_histogram_report(); void build_slack_histogram_report();
std::vector<CriticalPath> get_min_delay_violations();
dict<domain_id_t, delay_t> max_delay_by_domain_pairs(); dict<domain_id_t, delay_t> max_delay_by_domain_pairs();
// get the N worst endpoints for a given domain pair // get the N worst endpoints for a given domain pair