Added the --ignore-rel-clk option to control timing checks for cross-domain paths, formatted code

Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
This commit is contained in:
Maciej Kurc 2022-09-20 12:06:25 +02:00
parent 1f1bae3e23
commit 9000c41c4b
3 changed files with 105 additions and 112 deletions

View File

@ -172,6 +172,7 @@ po::options_description CommandHandler::getGeneralOptions()
general.add_options()("no-pack", "process design without packing"); general.add_options()("no-pack", "process design without packing");
general.add_options()("ignore-loops", "ignore combinational loops in timing analysis"); general.add_options()("ignore-loops", "ignore combinational loops in timing analysis");
general.add_options()("ignore-rel-clk", "ignore clock-to-clock relations in timing checks");
general.add_options()("version,V", "show version"); general.add_options()("version,V", "show version");
general.add_options()("test", "check architecture database integrity"); general.add_options()("test", "check architecture database integrity");
@ -270,6 +271,10 @@ void CommandHandler::setupContext(Context *ctx)
ctx->settings[ctx->id("timing/ignoreLoops")] = true; ctx->settings[ctx->id("timing/ignoreLoops")] = true;
} }
if (vm.count("ignore-rel-clk")) {
ctx->settings[ctx->id("timing/ignoreRelClk")] = true;
}
if (vm.count("timing-allow-fail")) { if (vm.count("timing-allow-fail")) {
ctx->settings[ctx->id("timing/allowFail")] = true; ctx->settings[ctx->id("timing/allowFail")] = true;
} }

View File

@ -285,7 +285,8 @@ void TimingAnalyser::setup_port_domains()
} }
} }
void TimingAnalyser::identify_related_domains() { void TimingAnalyser::identify_related_domains()
{
// Identify clock nets // Identify clock nets
pool<IdString> clock_nets; pool<IdString> clock_nets;
@ -296,8 +297,7 @@ void TimingAnalyser::identify_related_domains() {
// For each clock net identify all nets that can possibly drive it. Compute // For each clock net identify all nets that can possibly drive it. Compute
// cumulative delays to each of them. // cumulative delays to each of them.
std::function<void(const NetInfo *, dict<IdString, delay_t> &, delay_t)> find_net_drivers = std::function<void(const NetInfo *, dict<IdString, delay_t> &, delay_t)> find_net_drivers =
[&] (const NetInfo* ni, dict<IdString, delay_t>& drivers, delay_t delay_acc) [&](const NetInfo *ni, dict<IdString, delay_t> &drivers, delay_t delay_acc) {
{
// Get driving cell and port // Get driving cell and port
const CellInfo *cell = ni->driver.cell; const CellInfo *cell = ni->driver.cell;
const IdString port = ni->driver.port; const IdString port = ni->driver.port;
@ -369,11 +369,8 @@ void TimingAnalyser::identify_related_domains() {
log("Clock '%s' can be driven by:\n", domain.key.clock.str(ctx).c_str()); log("Clock '%s' can be driven by:\n", domain.key.clock.str(ctx).c_str());
for (const auto &it : drivers) { for (const auto &it : drivers) {
const NetInfo *net = ctx->nets.at(it.first).get(); const NetInfo *net = ctx->nets.at(it.first).get();
log(" %s.%s delay %.3fns\n", log(" %s.%s delay %.3fns\n", net->driver.cell->name.str(ctx).c_str(), net->driver.port.str(ctx).c_str(),
net->driver.cell->name.str(ctx).c_str(), ctx->getDelayNS(it.second));
net->driver.port.str(ctx).c_str(),
ctx->getDelayNS(it.second)
);
} }
} }
} }
@ -406,8 +403,8 @@ void TimingAnalyser::identify_related_domains() {
if (ctx->debug) { if (ctx->debug) {
log("Possible common driver(s) for clocks '%s' and '%s'\n", log("Possible common driver(s) for clocks '%s' and '%s'\n", c1.first.str(ctx).c_str(),
c1.first.str(ctx).c_str(), c2.first.str(ctx).c_str()); c2.first.str(ctx).c_str());
for (const auto &it : common_drivers) { for (const auto &it : common_drivers) {
@ -415,12 +412,8 @@ void TimingAnalyser::identify_related_domains() {
const CellInfo *cell = ni->driver.cell; const CellInfo *cell = ni->driver.cell;
const IdString port = ni->driver.port; const IdString port = ni->driver.port;
log(" net '%s', cell %s (%s), port %s\n", log(" net '%s', cell %s (%s), port %s\n", it.str(ctx).c_str(), cell->name.str(ctx).c_str(),
it.str(ctx).c_str(), cell->type.str(ctx).c_str(), port.str(ctx).c_str());
cell->name.str(ctx).c_str(),
cell->type.str(ctx).c_str(),
port.str(ctx).c_str()
);
} }
} }
@ -728,11 +721,8 @@ void TimingAnalyser::print_report()
print_fmax(); print_fmax();
for (const auto &it : clock_delays) { for (const auto &it : clock_delays) {
log_info("Clock-to-clock %s -> %s: %0.02f ns\n", log_info("Clock-to-clock %s -> %s: %0.02f ns\n", it.first.first.str(ctx).c_str(),
it.first.first.str(ctx).c_str(), it.first.second.str(ctx).c_str(), ctx->getDelayNS(it.second));
it.first.second.str(ctx).c_str(),
ctx->getDelayNS(it.second)
);
} }
} }
@ -1685,11 +1675,9 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
float target; float target;
if (clock_fmax.count(clock_a) && !clock_fmax.count(clock_b)) { if (clock_fmax.count(clock_a) && !clock_fmax.count(clock_b)) {
target = clock_fmax.at(clock_a).constraint; target = clock_fmax.at(clock_a).constraint;
} } else if (!clock_fmax.count(clock_a) && clock_fmax.count(clock_b)) {
else if (!clock_fmax.count(clock_a) && clock_fmax.count(clock_b)) {
target = clock_fmax.at(clock_b).constraint; target = clock_fmax.at(clock_b).constraint;
} } else {
else {
target = std::min(clock_fmax.at(clock_a).constraint, clock_fmax.at(clock_b).constraint); target = std::min(clock_fmax.at(clock_a).constraint, clock_fmax.at(clock_b).constraint);
} }
@ -1699,14 +1687,15 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
auto ev_b = format_event(report.clock_pair.end, max_width_xcb); auto ev_b = format_event(report.clock_pair.end, max_width_xcb);
if (!warn_on_failure || passed) if (!warn_on_failure || passed)
log_info("Max frequency for %s -> %s: %.02f MHz (%s at %.02f MHz)\n", log_info("Max frequency for %s -> %s: %.02f MHz (%s at %.02f MHz)\n", ev_a.c_str(), ev_b.c_str(),
ev_a.c_str(), ev_b.c_str(), fmax, passed ? "PASS" : "FAIL", target); fmax, passed ? "PASS" : "FAIL", target);
else if (bool_or_default(ctx->settings, ctx->id("timing/allowFail"), false)) else if (bool_or_default(ctx->settings, ctx->id("timing/allowFail"), false) ||
log_warning("Max frequency for %s -> %s: %.02f MHz (%s at %.02f MHz)\n", bool_or_default(ctx->settings, ctx->id("timing/ignoreRelClk"), false))
ev_a.c_str(), ev_b.c_str(), fmax, passed ? "PASS" : "FAIL", target); log_warning("Max frequency for %s -> %s: %.02f MHz (%s at %.02f MHz)\n", ev_a.c_str(),
ev_b.c_str(), fmax, passed ? "PASS" : "FAIL", target);
else else
log_nonfatal_error("Max frequency for %s -> %s: %.02f MHz (%s at %.02f MHz)\n", log_nonfatal_error("Max frequency for %s -> %s: %.02f MHz (%s at %.02f MHz)\n", ev_a.c_str(),
ev_a.c_str(), ev_b.c_str(), fmax, passed ? "PASS" : "FAIL", target); ev_b.c_str(), fmax, passed ? "PASS" : "FAIL", target);
} }
log_break(); log_break();
} }
@ -1722,7 +1711,8 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
delay /= 2; delay /= 2;
} }
log_info("Clock to clock delay %s -> %s: %0.02f ns\n", ev_a.c_str(), ev_b.c_str(), ctx->getDelayNS(delay)); log_info("Clock to clock delay %s -> %s: %0.02f ns\n", ev_a.c_str(), ev_b.c_str(),
ctx->getDelayNS(delay));
} }
log_break(); log_break();

View File

@ -92,9 +92,7 @@ struct TimingAnalyser
return slack; return slack;
} }
auto get_clock_delays () const { auto get_clock_delays() const { return clock_delays; }
return clock_delays;
}
bool setup_only = false; bool setup_only = false;
bool verbose_mode = false; bool verbose_mode = false;