timing: Add clock skew to arrival and required time

This commit is contained in:
Rowan Goemans 2024-09-12 19:49:35 +02:00 committed by myrtle
parent 60ee682d58
commit fc3b2de8da
3 changed files with 39 additions and 12 deletions

View File

@ -116,10 +116,10 @@ delay_t Context::predictArcDelay(const NetInfo *net_info, const PortRef &sink) c
delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &user_info) const delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &user_info) const
{ {
#ifdef ARCH_ECP5 // #ifdef ARCH_ECP5
if (net_info->is_global) // if (net_info->is_global)
return 0; // return 0;
#endif // #endif
if (net_info->wires.empty()) if (net_info->wires.empty())
return predictArcDelay(net_info, user_info); return predictArcDelay(net_info, user_info);

View File

@ -174,10 +174,20 @@ void TimingAnalyser::get_route_delays()
NetInfo *ni = net.second.get(); NetInfo *ni = net.second.get();
if (ni->driver.cell == nullptr || ni->driver.cell->bel == BelId()) if (ni->driver.cell == nullptr || ni->driver.cell->bel == BelId())
continue; continue;
if (clock_skew) {
printf("net %s has driver %s.%s\n", ni->name.c_str(ctx), ni->driver.cell->name.c_str(ctx),
ni->driver.port.c_str(ctx));
}
for (auto &usr : ni->users) { for (auto &usr : ni->users) {
if (usr.cell->bel == BelId()) if (usr.cell->bel == BelId())
continue; continue;
ports.at(CellPortKey(usr)).route_delay = DelayPair(ctx->getNetinfoRouteDelay(ni, usr)); ports.at(CellPortKey(usr)).route_delay = DelayPair(ctx->getNetinfoRouteDelay(ni, usr));
if (clock_skew) {
printf("\tuser %s.%s, delay: %f\n", usr.cell->name.c_str(ctx), usr.port.c_str(ctx),
ctx->getDelayNS(ctx->getNetinfoRouteDelay(ni, usr)));
}
} }
} }
} }
@ -567,12 +577,15 @@ void TimingAnalyser::walk_forward()
auto &pd = ports.at(sp.first); auto &pd = ports.at(sp.first);
DelayPair init_arrival(0); DelayPair init_arrival(0);
CellPortKey clock_key; CellPortKey clock_key;
// TODO: clock routing delay, if analysis of that is enabled
if (sp.second != IdString()) { if (sp.second != IdString()) {
// clocked startpoints have a clock-to-out time // clocked startpoints have a clock-to-out time
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 += fanin.value.delayPair();
if (clock_skew) {
auto clock_delay = ports.at(CellPortKey(sp.first.cell, fanin.other_port)).route_delay;
init_arrival += clock_delay;
}
break; break;
} }
} }
@ -619,20 +632,28 @@ void TimingAnalyser::walk_backward()
auto &dom = domains.at(dom_id); auto &dom = domains.at(dom_id);
for (auto &ep : dom.endpoints) { for (auto &ep : dom.endpoints) {
auto &pd = ports.at(ep.first); auto &pd = ports.at(ep.first);
DelayPair init_setuphold(0); DelayPair init_required(0);
CellPortKey clock_key; CellPortKey clock_key;
// TODO: clock routing delay, if analysis of that is enabled // TODO: clock routing delay, if analysis of that is enabled
if (ep.second != IdString()) { if (ep.second != IdString()) {
// Add setup/hold time, if this endpoint is clocked // Add setup/hold time, if this endpoint is clocked
for (auto &fanin : pd.cell_arcs) { for (auto &fanin : pd.cell_arcs) {
if (fanin.type == CellArc::SETUP && fanin.other_port == ep.second) printf("walk bwd %s.%s, fanin: %s, arctype: %s\n", ep.first.cell.c_str(ctx),
init_setuphold.min_delay -= fanin.value.maxDelay(); ep.first.port.c_str(ctx), fanin.other_port.c_str(ctx), arcType_to_str(fanin.type).c_str());
if (fanin.type == CellArc::SETUP && fanin.other_port == ep.second) {
if (clock_skew) {
auto clock_delay = ports.at(CellPortKey(ep.first.cell, fanin.other_port)).route_delay;
init_required += clock_delay;
}
init_required.min_delay -= fanin.value.maxDelay();
}
if (fanin.type == CellArc::HOLD && fanin.other_port == ep.second) if (fanin.type == CellArc::HOLD && fanin.other_port == ep.second)
init_setuphold.max_delay -= fanin.value.maxDelay(); init_required.max_delay -= fanin.value.maxDelay();
} }
clock_key = CellPortKey(ep.first.cell, ep.second); clock_key = CellPortKey(ep.first.cell, ep.second);
} }
set_required_time(ep.first, dom_id, init_setuphold, 1, clock_key); set_required_time(ep.first, dom_id, init_required, 1, clock_key);
} }
} }
// Walk backwards in topological order // Walk backwards in topological order
@ -1211,6 +1232,8 @@ void timing_analysis(Context *ctx, bool print_slack_histogram, bool print_fmax,
bool update_results) bool update_results)
{ {
TimingAnalyser tmg(ctx); TimingAnalyser tmg(ctx);
tmg.setup_only = false;
tmg.clock_skew = true;
tmg.setup(ctx->detailed_timing_report, print_slack_histogram, print_path || print_fmax); tmg.setup(ctx->detailed_timing_report, print_slack_histogram, print_path || print_fmax);
auto &result = tmg.get_timing_result(); auto &result = tmg.get_timing_result();

View File

@ -98,6 +98,10 @@ struct TimingAnalyser
TimingResult &get_timing_result() { return result; } TimingResult &get_timing_result() { return result; }
// Enable analysis of clock skew between FFs.
// Only do this after legal placement
bool clock_skew = false;
bool setup_only = false; bool setup_only = false;
bool have_loops = false; bool have_loops = false;
bool updated_domains = false; bool updated_domains = false;