Validating that the timing constraints are correct


Quite often, the FPGA development tactic is to add functionality, fix whatever doesn't work, and repeat. It's easy to neglect the parts of the design that are possibly wrong, but yet don't pose a visible problem.

It's crucial to understand that an FPGA design may work perfectly fine even if timing constraints are applied incorrectly and even if they're not met: Proper usage of timing constraints is one of the key components for ensuring the stable and correct operation of the FPGA; yet lacking such doesn't necessarily mean an immediate failure. Rather, improper timing may lead to occasional malfunctions that can be highly confusing.

This page highlights some topics to keep in mind when looking for problems that stem from poor timing. One can wish to have the wisdom to make this checkup every now and then for the sake of it, but in real life most of us do this to solve a problem that appears to be a bit like witchcraft.

Read your timing report

All FPGA design toolsets emit timing reports. The most common reason we open them is when the tools fail to meet the timing constraints: That's where one can find the answer to what the failing paths are, and hopefully what can be done about the timing failure.

However there is a no less important reason to refer to the timing reports: To verify that the timing constraints are interpreted by the tools as intended, and hence that they are properly applied. It's a good habit to make this check occasionally, in particular after adding new timing constraints.

Since each FPGA design toolset produces these reports in different structures and formats, it's infeasible to relate to exactly which part in which reports says what. Accordingly, this page outlines the principles, which are common to all tools. As for your own timing reports' formats and capabilities, it's a good idea anyhow to take the time to learn them.

Another possible benefit of a timing report checkup is that it may reveal incorrect usage of logic. For example, if the design includes inadequate asynchronous logic or depends on clocks that can't be timed correctly, this can become evident as these paths can't be, and therefore aren't constrained properly.

On a different note, it's worth mentioning that IPs that are included in the design often contribute timing constraints of their own, which the tools add on top of those you provide. The paths that relate to these constraints are usually less suspicious, but they can add quite some weight to the timing report.

Unconstrained internal paths

For the sake of this discussion, a synchronous element is a flip-flop, block RAM, shift register or any other logic elements which samples its data input and/or changes its data output on the rising or falling edge of a clock.

All paths going from a synchronous element's data output to another synchronous element's data input must be timed, i.e. subject to timing constraints. The only exception is when the possibility of a timing violation is properly handled at the destination synchronous element, as when crossing clock domains between unrelated clocks, as explained in this page.

In other words, the path to any synchronous element must be timed, unless there's an explicit resynchronization mechanism in place to cover up for fact that the design tools don't take any responsibility on sampling the input signal in a predictable manner.

Sometimes it's enough with a single-line timing constraint that defines the reference clock, and the design tools take care of the rest. In other cases it requires more than so. In really bad cases, some internal paths remain unconstrained by mistake. There are several possible reasons for this, among others:

FPGA design tools support the generation of timing reports that list unconstrained paths, which are the paths for which no timing constraint was applied. In principle, this list should be empty: Paths that need no constraining should be explicitly defined as false paths in the timing constraint file. Such constraints don't change anything functionally for paths that weren't constrained anyhow, but they allow keeping the list of unconstrained paths in the timing report empty. This makes it easy to spot paths that are unintentionally left unconstrained. Furthermore, since the number of listed paths is limited, having some paths that are harmlessly unconstrained in this list can hide paths that definitely shouldn't be there.

But unfortunately, in some timing reports, the section for unconstrained paths may also include paths that have no reason to be constrained. For example, the path from the output of a clock buffer to the input of another another clock resource. As a result, the timing report may list a whole lot of paths as unconstrained, and yet that's perfectly fine. This makes it slightly more difficult to deduce the situation from the timing report, but this isn't really a problem, since such paths are commonly listed separately from paths that end at a flip-flop's data input or some other synchronous element. So it boils down to reading the report carefully and paying attention to what each group of listed paths means.

The default timing report is sometimes not verbose enough to contain this information. Any reasonable FPGA design tool allows the generation of an on-demand timing report that lists unconstrained paths, and the choice of how many of them to list for each group (10 is a reasonable number, even though the relevant lists should be completely empty).

Paths between clock domains

Internals paths that are clocked by different clocks at their source and destination must be constrained if the clocks are related (or more precisely, if the logic treats them as related). Otherwise, they shouldn't be, as this unnecessary restriction may waste fast routing resources and possibly cause the failure to meet timing. See this page on related vs. unrelated clocks.

Each toolset has its own way to automatically decide whether to consider a pair of clocks as related. There are also different methods to guide the tools on this matter, in particular by virtue of false path timing constraints. Tools with SDC syntax constraints (e.g. Vivado and Quartus) have a set_clock_groups constraint, which allows defining groups of related and unrelated clocks.

So the question is how to check whether clocks are considered related or not by the tools. The unfortunate answer is that each toolset has a different way. Vivado, for example, has a Clock Interaction Report, with a color diagram showing whether the paths from one clock to another have been timed (i.e. the clocks are considered related), have not been timed ("User Ignored Paths") or if some of the paths have been timed.

Alternatively, custom timing reports that are limited to certain groups of paths can be used to investigate this issue. The paths can be selected according to the clocks involved. It might also be beneficial to pin-point path groups by selecting specific logic elements, knowing that they are involved in clock domain crossings.

Even though it might be difficult, it's crucial to make a comprehensive review of which clock domain crossings the tools apply constraints on, and whether they are correct. At the same time, it's an opportunity to review if the logic design has resynchronization logic where it's needed. It's common to get confused about which signal is clocked with which clock, and end up with unsafe clock domain crossings.

It's important to make this review with each clock's nature in mind. For example, if two clocks from different oscillators have the same rated frequency, and hence have a similar definition in the timing constraints file, the tools might mistake them for related clocks and calculate the timing on paths crossing between them. Constraining such paths is meaningless, as there's no guarantee whatsoever on the phase relations between the two clocks. By itself, unnecessary constraining just makes it harder for the tools to meet timing, which can be pretty harmless. The real problem is that the timing report might mislead us into thinking that the clocks are actually related.

So just looking at the constraints and the timing reports, the paths between them might appear to be safe (i.e. not needing protection against timing violations) when in fact they aren't — the two clocks have nothing in common, except for approximately the same frequency. The only way to avoid mistakes of this sort is to understand how each clock is generated.

Unconstrained external paths

Paths to and from I/O pins should always be constrained, except for clock input pins and those with a special interface, e.g. gigabit transceivers, pins that are connected directly to a hardware processor on the FPGA's silicon etc. It's also forgivable not to constrain very slow interfaces, such as LEDs, pushbuttons and even I2C wires. But it's significantly better to assign false path constraints for such, as it keeps the list of unconstrained I/O pins empty in the timing report.

Many times it may seem meaningless to constrain external paths. For example, if there are several output pins that are all clocked by the same clock, and the correct timing is ensured by the fact that they all toggle simultaneously. A common way to implement this simultaneous toggling is using the flip-flop that is inside the I/O pin's dedicated logic, which delivers the best clock-to-output possible and also an impressively low skew between output pins.

This is however a good example for when constraining the output timing is important: By keeping the timing constraints tight, a low skew between these pins is ensured. When the dedicated I/O logic's flip-flop is used, tight timing constraints can be a way to force the tools to use it, or make sure that a failure to do so doesn't go unnoticed — should the tools not place the flip-flop as desired, timing fails.

For similar reasons, input pins should be tightly constrained as well.

When using timing constraints for the sake of a low skew between several pins, it's important to constrain I/O pins not just until the reported slack is nearly zero, but to verify that requiring tighter timing leads to a timing failure. This is because the I/O signal path may contain optional delay lines, which the tools may utilize in a counterintuitive manner. For example, Intel FPGA's Quartus may add some delay in the input path if there's timing budget surplus, which may be neither desired nor expected.

Incorrect false paths and otherwise relaxed timing

Sometimes timing constraints are applied, but they are too permissive. This is much harder to spot, as the related paths are timed, only with the wrong requirement.

There are several possible reasons for mishaps of this sort, among others:

There is no simple recipe to spot issues of this sort. Reading the timing report from top to bottom carefully is definitely a good idea, however even if the report displays 10 paths for each group, there's no guarantee that the problematic ones will happen to appear there. Or among any number of displayed paths, for that matter.

Another way to tackle this is reviewing the timing constraints as written. Since SDC (and SDC-like) constraints are written in Tcl, it's possible to evaluate the expressions that select the "from" and "to" logic elements in the constraints file as Tcl expressions, and read through the list of endpoints.

So if, for example this line appears in a Vivado .xdc file:

set_false_path -to [ get_pins -hier -filter {name =~ */pclk_i1_bufgctrl.pclk_i1/S*} ]

one can open the implemented design and list the destinations to which the false paths apply:

puts [join [ get_pins -hier -filter {name =~ */pclk_i1_bufgctrl.pclk_i1/S*} ] "\n" ]

The "puts" and "join" Tcl commands make sure that each element is listed in a separate line, so it's easy to read the output (which can be very long).

This kind of review of the constraints is important, but it likewise difficult, as it requires real brainwork.


Making sure that the tools enforce the correct timing limits on the various paths is a tricky task. It's a combination of knowing what the timing constraint statements mean exactly and knowing how to check the timing reports, to increase the chances of spotting mistakes.

But more than anything, it's about having the self-discipline to check and re-check this issue, in particular when the design appears to work fine.

Copyright © 2021-2022. All rights reserved. (42e6e8c4)