diff --git a/common/kernel/nextpnr_types.h b/common/kernel/nextpnr_types.h index ff3b656f..c806c186 100644 --- a/common/kernel/nextpnr_types.h +++ b/common/kernel/nextpnr_types.h @@ -447,11 +447,11 @@ struct CriticalPath // Clock pair ClockPair clock_pair; // Total path delay + // if sum < 0 this is a hold/min violation + // if delay.maxDelay() >= max_delay this is a setup/max violation DelayPair delay; - // if delay.minDelay() < bound.minDelay() then this is a hold violation - // if delay.maxDelay() > bound.maxDelay() then this is a setup violation - DelayPair bound; + delay_t max_delay; // Individual path segments std::vector segments; diff --git a/common/kernel/timing.cc b/common/kernel/timing.cc index 008eff50..7504ead2 100644 --- a/common/kernel/timing.cc +++ b/common/kernel/timing.cc @@ -911,22 +911,21 @@ CriticalPath TimingAnalyser::build_critical_path_report(domain_id_t domain_pair, report.clock_pair.end.clock = capture.clock; report.clock_pair.end.edge = capture.edge; - report.bound = DelayPair(0, ctx->getDelayFromNS(1.0e9 / ctx->setting("target_freq"))); + report.max_delay = ctx->getDelayFromNS(1.0e9 / ctx->setting("target_freq")); if (launch.edge != capture.edge) { - report.bound.max_delay = report.bound.max_delay / 2; + report.max_delay = report.max_delay / 2; } if (!launch.is_async() && ctx->nets.at(launch.clock)->clkconstr) { if (launch.edge == capture.edge) { - report.bound.max_delay = ctx->nets.at(launch.clock)->clkconstr->period.minDelay(); + report.max_delay = ctx->nets.at(launch.clock)->clkconstr->period.minDelay(); } else if (capture.edge == RISING_EDGE) { - report.bound.max_delay = ctx->nets.at(launch.clock)->clkconstr->low.minDelay(); + report.max_delay = ctx->nets.at(launch.clock)->clkconstr->low.minDelay(); } else if (capture.edge == FALLING_EDGE) { - report.bound.max_delay = ctx->nets.at(launch.clock)->clkconstr->high.minDelay(); + report.max_delay = ctx->nets.at(launch.clock)->clkconstr->high.minDelay(); } } - // Walk the min or max path backwards to find a single crit path auto crit_path_rev = walk_crit_path(domain_pair, endpoint, longest_path); auto crit_path = boost::adaptors::reverse(crit_path_rev); @@ -997,8 +996,6 @@ CriticalPath TimingAnalyser::build_critical_path_report(domain_id_t domain_pair, } } - // Calculate clock skew only if start- and endpoint are registered - // and either the clock domains are the same or related clock if (with_clock_skew && register_start && register_end && (same_clock || related_clock)) { auto clock_delay_launch = @@ -1070,8 +1067,6 @@ CriticalPath TimingAnalyser::build_critical_path_report(domain_id_t domain_pair, is_startpoint = false; } - // Add setup/hold time as final segment - // And add hold time as min bound if (register_end) { CriticalPath::Segment seg_logic; seg_logic.delay = DelayPair(0); @@ -1086,8 +1081,6 @@ CriticalPath TimingAnalyser::build_critical_path_report(domain_id_t domain_pair, seg_logic.to = seg_logic.from; seg_logic.net = IdString(); report.segments.push_back(seg_logic); - - report.bound.min_delay = ep_clk_info.hold.min_delay; } return report; @@ -1244,8 +1237,7 @@ std::vector TimingAnalyser::get_min_delay_violations() auto clocks = std::make_pair(launch_clock, capture_clock); auto related_clocks = clock_delays.count(clocks) > 0; - // Don't consider async paths and clocks without known relationships - if (launch_id == async_clock_id && launch_id != capture_id && !related_clocks) { + if (launch_id == async_clock_id || (launch_id != capture_id && !related_clocks)) { continue; } diff --git a/common/kernel/timing_log.cc b/common/kernel/timing_log.cc index c01b1159..77db543b 100644 --- a/common/kernel/timing_log.cc +++ b/common/kernel/timing_log.cc @@ -74,9 +74,9 @@ static void log_crit_paths(const Context *ctx, TimingResult &result) // We print out the max delay since that's usually the interesting case // But if we know this critical path has violated hold time we print the // min delay instead - bool hold_violation = path.delay.minDelay() < path.bound.minDelay(); - auto get_delay_ns = [hold_violation, ctx](const DelayPair &d) { - if (hold_violation) { + bool min_delay_violation = path.delay.minDelay() < 0; + auto get_delay_ns = [min_delay_violation, ctx](const DelayPair &d) { + if (min_delay_violation) { ctx->getDelayNS(d.minDelay()); } return ctx->getDelayNS(d.maxDelay()); @@ -180,16 +180,16 @@ static void log_crit_paths(const Context *ctx, TimingResult &result) auto num_min_violations = result.min_delay_violations.size(); if (num_min_violations > 0) { log_break(); - log_info("Hold time/min time violation:\n"); + log_info("Hold time/min time violations:\n"); for (size_t i = 0; i < std::min((size_t)10, num_min_violations); ++i) { auto &report = result.min_delay_violations.at(i); 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_nonfatal_error("Hold time violations for clock '%s':\n", start.c_str()); + log_nonfatal_error("Hold time violation for clock '%s':\n", start.c_str()); } else { - log_nonfatal_error("Hold time violations for path '%s' -> '%s':\n", start.c_str(), end.c_str()); + log_nonfatal_error("Hold time violation for path '%s' -> '%s':\n", start.c_str(), end.c_str()); } print_path_report(report); }