fpga timing constraints

    FPGA Timing Constraints and Timing Closure: From "It Works on the Bench" to a Design That Always Meets Timing

    A practical guide to FPGA timing: what setup and hold slack mean, how to write clock and I/O constraints, handling clock domain crossings, reading the timing report, and the fixes that actually close timing.

    ·XTELL Engineering Team

    Why "it works on the bench" is not enough

    An FPGA design that runs correctly on one board at one temperature may still be wrong. If the tools were never told how fast the clocks are, or how the outside world delivers data, they place and route for something other than your real requirements, and the design passes by luck. Another build, another board, a hotter day or a slightly slower chip, and it fails in ways that look like random glitches. Timing constraints are how you tell the tools what correct means, and timing closure is the work of making the result meet it with margin.

    The two numbers that matter: setup and hold

    Every register captures its input on a clock edge, and the input must be stable for a short time before the edge (setup) and after it (hold). The tools check both for every path between registers.

    • Setup slack is how much time is left over on the longest path: the clock period, minus the launching register's clock-to-output delay, the logic delay, the routing delay and the receiving register's setup time. A negative number means the data arrives too late and the path fails at that clock speed. A made-up example at a 10 ns period: 10 − 0.4 (clock to output) − 6.0 (logic) − 3.2 (routing) − 0.3 (setup) = 0.1 ns of slack. It passes, with no room to spare.
    • Hold slack is the margin on the shortest path: new data must not arrive before the old data has been safely captured. Hold failures do not depend on the clock period, so slowing the clock does not cure them, and the tools normally fix them by adding delay in routing.

    The report summarises these as the worst negative slack (WNS), the total negative slack (TNS) and the number of failing endpoints. The goal is positive slack on every path, in every operating condition the tools model.

    What you must tell the tools

    The constraint formats used by the main vendors are based on the same SDC command set, with small differences, so the ideas carry over from one toolchain to another.

    1. Clocks

    Define every clock that enters the design, with its period. Outputs of clock-management blocks (PLLs and similar) are usually derived automatically, but check the report to see that they are, and define generated clocks yourself for any divider you build in logic.

    2. Inputs and outputs

    The tools cannot see outside the chip. For each interface you state how the data arrives and leaves relative to the clock: the largest and smallest delay between the clock edge and the data at the pin, which come from the external device's datasheet and the board delay.

    create_clock -name clk_100 -period 10.000 [get_ports clk_100]
    
    # data from an external device, with its datasheet delays
    set_input_delay  -clock clk_100 -max 3.0 [get_ports data_in*]
    set_input_delay  -clock clk_100 -min 0.5 [get_ports data_in*]
    
    # data to an external device
    set_output_delay -clock clk_100 -max 2.0 [get_ports data_out*]
    set_output_delay -clock clk_100 -min -0.5 [get_ports data_out*]

    Without these, the tools treat the pins as unconstrained and report nothing about them, and a design with unconstrained interfaces can look clean in the report while failing in the system.

    3. Clock domain crossings

    Signals that pass from one clock to an unrelated one cannot meet ordinary timing, and should not be asked to. They must be made safe by design: a two-flip-flop synchroniser for a single-bit level, a handshake for a multi-bit value, an asynchronous FIFO with Gray-coded pointers for a stream. Then tell the tools the clocks are unrelated, so they stop checking those paths as if they were synchronous:

    set_clock_groups -asynchronous \
        -group [get_clocks clk_100] \
        -group [get_clocks clk_adc]

    This is the most abused constraint in FPGA design. A false path or an asynchronous group declared on a path that is in fact synchronous hides a real failure, so each one should have a written reason, and the crossings themselves should be reviewed as a separate task.

    4. Exceptions

    A multicycle path tells the tools that data is allowed more than one clock period to arrive, for example when a register updates every fourth cycle. It must match what the design really does, including the enable logic.

    Read the report like an engineer

    • Start with the check that nothing is unconstrained: no unconstrained clocks, inputs or outputs, and no paths that were ignored by mistake.
    • Look at the failing paths in order of how bad they are, and read each one end to end: the source and destination registers, the number of logic levels, the fan-out, how much of the delay is routing against logic.
    • Group failures by cause. Fifty failing paths are often one problem: a slow clock enable, a high-fan-out reset, one large multiplexer.
    • Check the results across the process, voltage and temperature corners that the tools model, and keep some margin beyond zero, since a design with 20 ps of slack is a design that fails when the next change moves a placement.

    Fixes that actually close timing

    Try them in this order, since the earlier ones cost less.

    1. Reduce logic levels with pipelining. Put a register in the middle of a long combinational path. This costs a cycle of latency and often a little area, and is the most reliable fix.
    2. Cut fan-out. A signal driving hundreds of loads has a long routing delay. Duplicate the register and let each copy drive a part of the load.
    3. Use the dedicated blocks. Multipliers, memory and arithmetic carry chains are faster in the built-in blocks than in general logic, and register the inputs and outputs of those blocks.
    4. Register the I/O. Registers placed in the I/O cells shorten the path to the pin and make interface timing predictable.
    5. Clock enables instead of gated clocks. Gating a clock in logic breaks the clock network and the timing analysis. Use an enable on the register.
    6. Guide the placement. When two blocks that talk constantly are placed far apart, constrain their region, or revisit the design to separate them logically. Reach for this late, since it makes the result more fragile.
    7. Change the tool settings, such as an effort level, retiming or physical optimisation, after the structure is sound. Settings can give a few percent, not a rescue.

    Make closure a habit, not a rescue

    • Write the constraints at the start of the project, and run the timing report on every build, not just at the end.
    • Treat a new timing failure as a bug in the change that introduced it, and fix it before moving on.
    • Keep the constraints in version control with the source, and review changes to them as carefully as code.
    • Choose the target clock rate with a margin below what the device can do. A design pushed to the limit of the fabric closes slowly, and every later feature costs a fight.

    In our work

    We bring up FPGA designs on Lattice, Microchip PolarFire and Xilinx devices, including the fiber signal communication board where a Lattice FPGA handles a 14-bit, 80 MSPS converter and a 16-bit, 50 MSPS converter. In that kind of design the interface timing is the design. If you want constraints, clock-domain crossings and timing closure handled as part of the whole system, see our FPGA design service, and our guide to choosing an FPGA for an embedded product.

    Need Professional Services?

    Contact us for customized solutions and quotes