timing: Start identification of min_delay violations
This commit is contained in:
parent
44665a9c4d
commit
c25da06d03
@ -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<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)
|
||||
{
|
||||
return domain_id(ctx->cells.at(cell)->ports.at(clock_port).net, edge);
|
||||
|
@ -125,6 +125,8 @@ struct TimingAnalyser
|
||||
void build_crit_path_reports();
|
||||
void build_slack_histogram_report();
|
||||
|
||||
std::vector<CriticalPath> get_min_delay_violations();
|
||||
|
||||
dict<domain_id_t, delay_t> max_delay_by_domain_pairs();
|
||||
|
||||
// get the N worst endpoints for a given domain pair
|
||||
|
Loading…
Reference in New Issue
Block a user