timing: Report min delay violated in timing logger
This commit is contained in:
parent
7aeed52c06
commit
82ea65d984
@ -25,7 +25,6 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "log.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
@ -75,7 +74,6 @@ 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -575,8 +573,6 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -597,10 +593,6 @@ void TimingAnalyser::walk_forward()
|
|||||||
CellPortKey usr_key(usr);
|
CellPortKey usr_key(usr);
|
||||||
auto &usr_pd = ports.at(usr_key);
|
auto &usr_pd = ports.at(usr_key);
|
||||||
auto next_arr = arr.second.value + usr_pd.route_delay;
|
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);
|
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) {
|
||||||
@ -610,10 +602,6 @@ void TimingAnalyser::walk_forward()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto next_arr = arr.second.value + fanout.value.delayPair();
|
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,
|
set_arrival_time(CellPortKey(p.cell, fanout.other_port), arr.first, next_arr,
|
||||||
arr.second.path_length + 1, p);
|
arr.second.path_length + 1, p);
|
||||||
}
|
}
|
||||||
@ -730,13 +718,6 @@ 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);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -869,13 +850,6 @@ CriticalPath TimingAnalyser::build_critical_path_report(domain_id_t domain_pair,
|
|||||||
std::vector<PortRef> crit_path_rev;
|
std::vector<PortRef> crit_path_rev;
|
||||||
auto cursor = endpoint;
|
auto cursor = endpoint;
|
||||||
|
|
||||||
auto next_cursor = [longest_path](ArrivReqTime &arrival) {
|
|
||||||
if (longest_path) {
|
|
||||||
return arrival.bwd_max;
|
|
||||||
}
|
|
||||||
return arrival.bwd_min;
|
|
||||||
};
|
|
||||||
|
|
||||||
while (cursor != CellPortKey()) {
|
while (cursor != CellPortKey()) {
|
||||||
auto cell = cell_info(cursor);
|
auto cell = cell_info(cursor);
|
||||||
auto &port = port_info(cursor);
|
auto &port = port_info(cursor);
|
||||||
@ -892,7 +866,11 @@ CriticalPath TimingAnalyser::build_critical_path_report(domain_id_t domain_pair,
|
|||||||
if (!ports.at(cursor).arrival.count(dp.key.launch))
|
if (!ports.at(cursor).arrival.count(dp.key.launch))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
cursor = next_cursor(ports.at(cursor).arrival.at(dp.key.launch));
|
if (longest_path) {
|
||||||
|
cursor = ports.at(cursor).arrival.at(dp.key.launch).bwd_max;
|
||||||
|
} else {
|
||||||
|
cursor = ports.at(cursor).arrival.at(dp.key.launch).bwd_min;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto crit_path = boost::adaptors::reverse(crit_path_rev);
|
auto crit_path = boost::adaptors::reverse(crit_path_rev);
|
||||||
@ -989,6 +967,10 @@ void TimingAnalyser::build_crit_path_reports()
|
|||||||
auto &empty_clocks = result.empty_paths;
|
auto &empty_clocks = result.empty_paths;
|
||||||
auto &clock_delays_ctx = result.clock_delays;
|
auto &clock_delays_ctx = result.clock_delays;
|
||||||
|
|
||||||
|
if (!setup_only) {
|
||||||
|
result.min_delay_violations = get_min_delay_violations();
|
||||||
|
}
|
||||||
|
|
||||||
auto delay_by_domain = max_delay_by_domain_pairs();
|
auto delay_by_domain = max_delay_by_domain_pairs();
|
||||||
|
|
||||||
for (int i = 0; i < int(domains.size()); i++) {
|
for (int i = 0; i < int(domains.size()); i++) {
|
||||||
@ -1105,26 +1087,6 @@ 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> TimingAnalyser::get_min_delay_violations()
|
||||||
{
|
{
|
||||||
std::vector<CriticalPath> violations;
|
std::vector<CriticalPath> violations;
|
||||||
@ -1144,17 +1106,14 @@ std::vector<CriticalPath> TimingAnalyser::get_min_delay_violations()
|
|||||||
|
|
||||||
DelayPair period = clk_net->clkconstr->period;
|
DelayPair period = clk_net->clkconstr->period;
|
||||||
|
|
||||||
printf("Clock %s.%s with period %f - %f\n", clk_net->driver.cell->name.c_str(ctx),
|
for (auto &ep : capture.endpoints) {
|
||||||
clk_net->driver.port.c_str(ctx), ctx->getDelayNS(period.minDelay()), ctx->getDelayNS(period.maxDelay()));
|
CellInfo *ci = cell_info(ep.first);
|
||||||
|
|
||||||
for (auto &sp : capture.endpoints) {
|
|
||||||
CellInfo *ci = cell_info(sp.first);
|
|
||||||
int clkInfoCount = 0;
|
int clkInfoCount = 0;
|
||||||
TimingPortClass cls = ctx->getPortTimingClass(ci, sp.first.port, clkInfoCount);
|
TimingPortClass cls = ctx->getPortTimingClass(ci, ep.first.port, clkInfoCount);
|
||||||
if (cls != TMG_REGISTER_INPUT)
|
if (cls != TMG_REGISTER_INPUT)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto &port = ports.at(sp.first);
|
auto &port = ports.at(ep.first);
|
||||||
|
|
||||||
auto &req = port.required.at(capture_id);
|
auto &req = port.required.at(capture_id);
|
||||||
|
|
||||||
@ -1177,10 +1136,12 @@ std::vector<CriticalPath> TimingAnalyser::get_min_delay_violations()
|
|||||||
|
|
||||||
auto hold_slack = arr.value.minDelay() - req.value.maxDelay() + clock_to_clock;
|
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),
|
auto violated = true;
|
||||||
sp.first.port.c_str(ctx), ctx->getDelayNS(arr.value.minDelay()),
|
|
||||||
ctx->getDelayNS(arr.value.maxDelay()), ctx->getDelayNS(req.value.minDelay()),
|
if (violated) {
|
||||||
ctx->getDelayNS(req.value.maxDelay()), ctx->getDelayNS(hold_slack));
|
const auto dom_pair_id = domain_pair_id(launch_id, capture_id);
|
||||||
|
violations.emplace_back(build_critical_path_report(dom_pair_id, ep.first, false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1222,6 +1183,26 @@ void TimingAnalyser::copy_domains(const CellPortKey &from, const CellPortKey &to
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string TimingAnalyser::arcType_to_str(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:
|
||||||
|
log_error("Impossible CellArc::ArcType\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CellInfo *TimingAnalyser::cell_info(const CellPortKey &key) { return ctx->cells.at(key.cell).get(); }
|
CellInfo *TimingAnalyser::cell_info(const CellPortKey &key) { return ctx->cells.at(key.cell).get(); }
|
||||||
|
|
||||||
PortInfo &TimingAnalyser::port_info(const CellPortKey &key) { return ctx->cells.at(key.cell)->ports.at(key.port); }
|
PortInfo &TimingAnalyser::port_info(const CellPortKey &key) { return ctx->cells.at(key.cell)->ports.at(key.port); }
|
||||||
|
@ -225,6 +225,8 @@ struct TimingAnalyser
|
|||||||
|
|
||||||
void copy_domains(const CellPortKey &from, const CellPortKey &to, bool backwards);
|
void copy_domains(const CellPortKey &from, const CellPortKey &to, bool backwards);
|
||||||
|
|
||||||
|
[[maybe_unused]] static const std::string arcType_to_str(CellArc::ArcType typ);
|
||||||
|
|
||||||
dict<CellPortKey, PerPort> ports;
|
dict<CellPortKey, PerPort> ports;
|
||||||
dict<ClockDomainKey, domain_id_t> domain_to_id;
|
dict<ClockDomainKey, domain_id_t> domain_to_id;
|
||||||
dict<ClockDomainPairKey, domain_id_t> pair_to_id;
|
dict<ClockDomainPairKey, domain_id_t> pair_to_id;
|
||||||
|
@ -168,7 +168,20 @@ static void log_crit_paths(const Context *ctx, TimingResult &result)
|
|||||||
log_info("Critical path report for cross-domain path '%s' -> '%s':\n", start.c_str(), end.c_str());
|
log_info("Critical path report for cross-domain path '%s' -> '%s':\n", start.c_str(), end.c_str());
|
||||||
print_path_report(report);
|
print_path_report(report);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
// Min delay violated paths
|
||||||
|
for (auto &report : result.min_delay_violations) {
|
||||||
|
log_break();
|
||||||
|
std::string start = clock_event_name(ctx, report.clock_pair.start);
|
||||||
|
std::string end = clock_event_name(ctx, report.clock_pair.end);
|
||||||
|
if (report.clock_pair.start == report.clock_pair.end) {
|
||||||
|
log_info("Hold time violations for clock '%s':\n", start.c_str());
|
||||||
|
} else {
|
||||||
|
log_info("Hold time violations for path '%s' -> '%s':\n", start.c_str(), end.c_str());
|
||||||
|
}
|
||||||
|
print_path_report(report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void log_fmax(Context *ctx, TimingResult &result, bool warn_on_failure)
|
static void log_fmax(Context *ctx, TimingResult &result, bool warn_on_failure)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user